diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000000..178bcbce24a --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 7fa7496cedd22a33b10cd91d84b7920f +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.circleci/config.yml b/.circleci/config.yml index 9f803ece4ac..075a613be0d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ orbs: jobs: build_doc: docker: - - image: cimg/python:3.12 + - image: cimg/python:3.10 steps: - checkout - run: diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 0d943696cce..24f09262998 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ # These are supported funding model platforms github: AtsushiSakai patreon: myenigma -custom: https://www.paypal.com/paypalme/myenigmapay/ +custom: https://www.paypal.me/myenigmapay/ diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6ffedf6f3b7..07f1bc80e06 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,8 +6,3 @@ updates: interval: weekly time: "20:00" open-pull-requests-limit: 10 - -- package-ecosystem: github-actions - directory: "/" - schedule: - interval: weekly diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b6ac52efa24..c5410631563 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,7 @@ <!-- Thanks for contributing a pull request! Please check this document before submitting: -- [How to contribute](https://atsushisakai.github.io/PythonRobotics/how_to_contribute.html#adding-a-new-algorithm-example) +- [How to contribute](https://pythonrobotics.readthedocs.io/en/latest/how_to_contribute.html#adding-a-new-algorithm-example) Note that this is my hobby project; I appreciate your patience during the review process. @@ -19,6 +19,6 @@ Again, thanks for contributing! <!--Any additional information you think is important.--> #### CheckList -- [ ] Did you add an unittest for your new example or defect fix? -- [ ] Did you add documents for your new example? -- [ ] All CIs are green? (You can check it after submitting) +-[] Did you add an unittest for your new example or defect fix? +-[] Did you add documents for your new example? +-[] All CIs are green? (You can check it after submitting) diff --git a/.github/workflows/Linux_CI.yml b/.github/workflows/Linux_CI.yml index 7b3dc14751a..73f8aa5c0d0 100644 --- a/.github/workflows/Linux_CI.yml +++ b/.github/workflows/Linux_CI.yml @@ -12,16 +12,16 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.12' ] + python-version: ['3.10'] name: Python ${{ matrix.python-version }} CI steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - run: git fetch --prune --unshallow - name: Setup python - uses: actions/setup-python@v5 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.github/workflows/MacOS_CI.yml b/.github/workflows/MacOS_CI.yml index 5ea15ac72e3..5c796120a51 100644 --- a/.github/workflows/MacOS_CI.yml +++ b/.github/workflows/MacOS_CI.yml @@ -16,17 +16,17 @@ jobs: runs-on: macos-latest strategy: matrix: - python-version: [ '3.12' ] + python-version: [ '3.10' ] name: Python ${{ matrix.python-version }} CI steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - run: git fetch --prune --unshallow - name: Update bash run: brew install bash - name: Setup python - uses: actions/setup-python@v5 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} @@ -36,4 +36,4 @@ jobs: python -m pip install --upgrade pip pip install -r requirements/requirements.txt - name: do all unit tests - run: bash runtests.sh + run: bash runtests.sh \ No newline at end of file diff --git a/.github/workflows/Windows_CI.yml b/.github/workflows/Windows_CI.yml deleted file mode 100644 index b9c8dea649c..00000000000 --- a/.github/workflows/Windows_CI.yml +++ /dev/null @@ -1,36 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Windows_CI - -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch -on: - push: - branches: - - master - pull_request: - - -jobs: - build: - runs-on: windows-latest - strategy: - matrix: - python-version: [ '3.12' ] - name: Python ${{ matrix.python-version }} CI - steps: - - uses: actions/checkout@v4 - - run: git fetch --prune --unshallow - - - name: Setup python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python --version - python -m pip install --upgrade pip - pip install -r requirements/requirements.txt - - name: do all unit tests - run: bash runtests.sh diff --git a/.github/workflows/circle_artifacts.yml b/.github/workflows/circle_artifacts.yml new file mode 100644 index 00000000000..56ac78ed152 --- /dev/null +++ b/.github/workflows/circle_artifacts.yml @@ -0,0 +1,13 @@ +on: [status] +jobs: + circleci_artifacts_redirector_job: + runs-on: ubuntu-20.04 + name: Run CircleCI artifacts redirector + steps: + - name: GitHub Action step + uses: larsoner/circleci-artifacts-redirector-action@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + artifact-path: 0/html-scipyorg/index.html + circleci-jobs: build_docs + job-title: build_doc artifact \ No newline at end of file diff --git a/.github/workflows/circleci-artifacts-redirector.yml b/.github/workflows/circleci-artifacts-redirector.yml index 78eb479aa16..d988d2c38ef 100644 --- a/.github/workflows/circleci-artifacts-redirector.yml +++ b/.github/workflows/circleci-artifacts-redirector.yml @@ -3,12 +3,11 @@ on: [status] jobs: circleci_artifacts_redirector_job: runs-on: ubuntu-latest - name: Run CircleCI artifacts redirector!! + name: Run CircleCI artifacts redirector steps: - name: run-circleci-artifacts-redirector - uses: larsoner/circleci-artifacts-redirector-action@v1.0.0 + uses: larsoner/circleci-artifacts-redirector-action@0.3.1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - api-token: ${{ secrets.CIRCLECI_TOKEN }} artifact-path: 0/html/index.html circleci-jobs: build_doc diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 878a4a44359..148260a835b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v2 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -24,7 +24,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v1 with: config-file: ./.github/codeql/codeql-config.yml # Override language selection by uncommenting this and choosing your languages @@ -34,7 +34,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -48,4 +48,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index e08c6106c08..e51197cb37c 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -1,4 +1,4 @@ -name: GitHub Pages site update +name: Pages on: push: branches: @@ -6,15 +6,9 @@ on: jobs: build: runs-on: ubuntu-latest - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - permissions: - id-token: write - pages: write steps: - name: Setup python - uses: actions/setup-python@v5 + uses: actions/setup-python@v2 - name: Checkout uses: actions/checkout@master with: @@ -24,7 +18,12 @@ jobs: python --version python -m pip install --upgrade pip python -m pip install -r requirements/requirements.txt - - name: Build and Deploy - uses: sphinx-notes/pages@v3 + - name: Build and Commit + uses: sphinx-notes/pages@v2 with: - requirements_path: ./docs/doc_requirements.txt + requirements_path: ./docs/doc_requirements.txt + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: gh-pages \ No newline at end of file diff --git a/.lgtm.yml b/.lgtm.yml new file mode 100644 index 00000000000..b06edf35106 --- /dev/null +++ b/.lgtm.yml @@ -0,0 +1,4 @@ +extraction: + python: + python_setup: + version: 3 diff --git a/AerialNavigation/__init__.py b/.nojekyll similarity index 100% rename from AerialNavigation/__init__.py rename to .nojekyll diff --git a/AerialNavigation/drone_3d_trajectory_following/Quadrotor.py b/AerialNavigation/drone_3d_trajectory_following/Quadrotor.py deleted file mode 100644 index c379e5eda0e..00000000000 --- a/AerialNavigation/drone_3d_trajectory_following/Quadrotor.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Class for plotting a quadrotor - -Author: Daniel Ingram (daniel-s-ingram) -""" - -from math import cos, sin -import numpy as np -import matplotlib.pyplot as plt - -class Quadrotor(): - def __init__(self, x=0, y=0, z=0, roll=0, pitch=0, yaw=0, size=0.25, show_animation=True): - self.p1 = np.array([size / 2, 0, 0, 1]).T - self.p2 = np.array([-size / 2, 0, 0, 1]).T - self.p3 = np.array([0, size / 2, 0, 1]).T - self.p4 = np.array([0, -size / 2, 0, 1]).T - - self.x_data = [] - self.y_data = [] - self.z_data = [] - self.show_animation = show_animation - - if self.show_animation: - plt.ion() - fig = plt.figure() - # for stopping simulation with the esc key. - fig.canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - self.ax = fig.add_subplot(111, projection='3d') - - self.update_pose(x, y, z, roll, pitch, yaw) - - def update_pose(self, x, y, z, roll, pitch, yaw): - self.x = x - self.y = y - self.z = z - self.roll = roll - self.pitch = pitch - self.yaw = yaw - self.x_data.append(x) - self.y_data.append(y) - self.z_data.append(z) - - if self.show_animation: - self.plot() - - def transformation_matrix(self): - x = self.x - y = self.y - z = self.z - roll = self.roll - pitch = self.pitch - yaw = self.yaw - return np.array( - [[cos(yaw) * cos(pitch), -sin(yaw) * cos(roll) + cos(yaw) * sin(pitch) * sin(roll), sin(yaw) * sin(roll) + cos(yaw) * sin(pitch) * cos(roll), x], - [sin(yaw) * cos(pitch), cos(yaw) * cos(roll) + sin(yaw) * sin(pitch) - * sin(roll), -cos(yaw) * sin(roll) + sin(yaw) * sin(pitch) * cos(roll), y], - [-sin(pitch), cos(pitch) * sin(roll), cos(pitch) * cos(roll), z] - ]) - - def plot(self): # pragma: no cover - T = self.transformation_matrix() - - p1_t = np.matmul(T, self.p1) - p2_t = np.matmul(T, self.p2) - p3_t = np.matmul(T, self.p3) - p4_t = np.matmul(T, self.p4) - - plt.cla() - - self.ax.plot([p1_t[0], p2_t[0], p3_t[0], p4_t[0]], - [p1_t[1], p2_t[1], p3_t[1], p4_t[1]], - [p1_t[2], p2_t[2], p3_t[2], p4_t[2]], 'k.') - - self.ax.plot([p1_t[0], p2_t[0]], [p1_t[1], p2_t[1]], - [p1_t[2], p2_t[2]], 'r-') - self.ax.plot([p3_t[0], p4_t[0]], [p3_t[1], p4_t[1]], - [p3_t[2], p4_t[2]], 'r-') - - self.ax.plot(self.x_data, self.y_data, self.z_data, 'b:') - - plt.xlim(-5, 5) - plt.ylim(-5, 5) - self.ax.set_zlim(0, 10) - - plt.pause(0.001) diff --git a/AerialNavigation/drone_3d_trajectory_following/TrajectoryGenerator.py b/AerialNavigation/drone_3d_trajectory_following/TrajectoryGenerator.py deleted file mode 100644 index 0b99af885c4..00000000000 --- a/AerialNavigation/drone_3d_trajectory_following/TrajectoryGenerator.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Generates a quintic polynomial trajectory. - -Author: Daniel Ingram (daniel-s-ingram) -""" - -import numpy as np - -class TrajectoryGenerator(): - def __init__(self, start_pos, des_pos, T, start_vel=[0,0,0], des_vel=[0,0,0], start_acc=[0,0,0], des_acc=[0,0,0]): - self.start_x = start_pos[0] - self.start_y = start_pos[1] - self.start_z = start_pos[2] - - self.des_x = des_pos[0] - self.des_y = des_pos[1] - self.des_z = des_pos[2] - - self.start_x_vel = start_vel[0] - self.start_y_vel = start_vel[1] - self.start_z_vel = start_vel[2] - - self.des_x_vel = des_vel[0] - self.des_y_vel = des_vel[1] - self.des_z_vel = des_vel[2] - - self.start_x_acc = start_acc[0] - self.start_y_acc = start_acc[1] - self.start_z_acc = start_acc[2] - - self.des_x_acc = des_acc[0] - self.des_y_acc = des_acc[1] - self.des_z_acc = des_acc[2] - - self.T = T - - def solve(self): - A = np.array( - [[0, 0, 0, 0, 0, 1], - [self.T**5, self.T**4, self.T**3, self.T**2, self.T, 1], - [0, 0, 0, 0, 1, 0], - [5*self.T**4, 4*self.T**3, 3*self.T**2, 2*self.T, 1, 0], - [0, 0, 0, 2, 0, 0], - [20*self.T**3, 12*self.T**2, 6*self.T, 2, 0, 0] - ]) - - b_x = np.array( - [[self.start_x], - [self.des_x], - [self.start_x_vel], - [self.des_x_vel], - [self.start_x_acc], - [self.des_x_acc] - ]) - - b_y = np.array( - [[self.start_y], - [self.des_y], - [self.start_y_vel], - [self.des_y_vel], - [self.start_y_acc], - [self.des_y_acc] - ]) - - b_z = np.array( - [[self.start_z], - [self.des_z], - [self.start_z_vel], - [self.des_z_vel], - [self.start_z_acc], - [self.des_z_acc] - ]) - - self.x_c = np.linalg.solve(A, b_x) - self.y_c = np.linalg.solve(A, b_y) - self.z_c = np.linalg.solve(A, b_z) \ No newline at end of file diff --git a/AerialNavigation/drone_3d_trajectory_following/__init__.py b/AerialNavigation/drone_3d_trajectory_following/__init__.py deleted file mode 100644 index 2194d4c3033..00000000000 --- a/AerialNavigation/drone_3d_trajectory_following/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent)) diff --git a/AerialNavigation/drone_3d_trajectory_following/drone_3d_trajectory_following.py b/AerialNavigation/drone_3d_trajectory_following/drone_3d_trajectory_following.py deleted file mode 100644 index 029e82be62d..00000000000 --- a/AerialNavigation/drone_3d_trajectory_following/drone_3d_trajectory_following.py +++ /dev/null @@ -1,213 +0,0 @@ -""" -Simulate a quadrotor following a 3D trajectory - -Author: Daniel Ingram (daniel-s-ingram) -""" - -from math import cos, sin -import numpy as np -from Quadrotor import Quadrotor -from TrajectoryGenerator import TrajectoryGenerator - -show_animation = True - -# Simulation parameters -g = 9.81 -m = 0.2 -Ixx = 1 -Iyy = 1 -Izz = 1 -T = 5 - -# Proportional coefficients -Kp_x = 1 -Kp_y = 1 -Kp_z = 1 -Kp_roll = 25 -Kp_pitch = 25 -Kp_yaw = 25 - -# Derivative coefficients -Kd_x = 10 -Kd_y = 10 -Kd_z = 1 - - -def quad_sim(x_c, y_c, z_c): - """ - Calculates the necessary thrust and torques for the quadrotor to - follow the trajectory described by the sets of coefficients - x_c, y_c, and z_c. - """ - x_pos = -5 - y_pos = -5 - z_pos = 5 - x_vel = 0 - y_vel = 0 - z_vel = 0 - x_acc = 0 - y_acc = 0 - z_acc = 0 - roll = 0 - pitch = 0 - yaw = 0 - roll_vel = 0 - pitch_vel = 0 - yaw_vel = 0 - - des_yaw = 0 - - dt = 0.1 - t = 0 - - q = Quadrotor(x=x_pos, y=y_pos, z=z_pos, roll=roll, - pitch=pitch, yaw=yaw, size=1, show_animation=show_animation) - - i = 0 - n_run = 8 - irun = 0 - - while True: - while t <= T: - # des_x_pos = calculate_position(x_c[i], t) - # des_y_pos = calculate_position(y_c[i], t) - des_z_pos = calculate_position(z_c[i], t) - # des_x_vel = calculate_velocity(x_c[i], t) - # des_y_vel = calculate_velocity(y_c[i], t) - des_z_vel = calculate_velocity(z_c[i], t) - des_x_acc = calculate_acceleration(x_c[i], t) - des_y_acc = calculate_acceleration(y_c[i], t) - des_z_acc = calculate_acceleration(z_c[i], t) - - thrust = m * (g + des_z_acc + Kp_z * (des_z_pos - - z_pos) + Kd_z * (des_z_vel - z_vel)) - - roll_torque = Kp_roll * \ - (((des_x_acc * sin(des_yaw) - des_y_acc * cos(des_yaw)) / g) - roll) - pitch_torque = Kp_pitch * \ - (((des_x_acc * cos(des_yaw) - des_y_acc * sin(des_yaw)) / g) - pitch) - yaw_torque = Kp_yaw * (des_yaw - yaw) - - roll_vel += roll_torque * dt / Ixx - pitch_vel += pitch_torque * dt / Iyy - yaw_vel += yaw_torque * dt / Izz - - roll += roll_vel * dt - pitch += pitch_vel * dt - yaw += yaw_vel * dt - - R = rotation_matrix(roll, pitch, yaw) - acc = (np.matmul(R, np.array( - [0, 0, thrust.item()]).T) - np.array([0, 0, m * g]).T) / m - x_acc = acc[0] - y_acc = acc[1] - z_acc = acc[2] - x_vel += x_acc * dt - y_vel += y_acc * dt - z_vel += z_acc * dt - x_pos += x_vel * dt - y_pos += y_vel * dt - z_pos += z_vel * dt - - q.update_pose(x_pos, y_pos, z_pos, roll, pitch, yaw) - - t += dt - - t = 0 - i = (i + 1) % 4 - irun += 1 - if irun >= n_run: - break - - print("Done") - - -def calculate_position(c, t): - """ - Calculates a position given a set of quintic coefficients and a time. - - Args - c: List of coefficients generated by a quintic polynomial - trajectory generator. - t: Time at which to calculate the position - - Returns - Position - """ - return c[0] * t**5 + c[1] * t**4 + c[2] * t**3 + c[3] * t**2 + c[4] * t + c[5] - - -def calculate_velocity(c, t): - """ - Calculates a velocity given a set of quintic coefficients and a time. - - Args - c: List of coefficients generated by a quintic polynomial - trajectory generator. - t: Time at which to calculate the velocity - - Returns - Velocity - """ - return 5 * c[0] * t**4 + 4 * c[1] * t**3 + 3 * c[2] * t**2 + 2 * c[3] * t + c[4] - - -def calculate_acceleration(c, t): - """ - Calculates an acceleration given a set of quintic coefficients and a time. - - Args - c: List of coefficients generated by a quintic polynomial - trajectory generator. - t: Time at which to calculate the acceleration - - Returns - Acceleration - """ - return 20 * c[0] * t**3 + 12 * c[1] * t**2 + 6 * c[2] * t + 2 * c[3] - - -def rotation_matrix(roll_array, pitch_array, yaw): - """ - Calculates the ZYX rotation matrix. - - Args - Roll: Angular position about the x-axis in radians. - Pitch: Angular position about the y-axis in radians. - Yaw: Angular position about the z-axis in radians. - - Returns - 3x3 rotation matrix as NumPy array - """ - roll = roll_array[0] - pitch = pitch_array[0] - return np.array( - [[cos(yaw) * cos(pitch), -sin(yaw) * cos(roll) + cos(yaw) * sin(pitch) * sin(roll), sin(yaw) * sin(roll) + cos(yaw) * sin(pitch) * cos(roll)], - [sin(yaw) * cos(pitch), cos(yaw) * cos(roll) + sin(yaw) * sin(pitch) * - sin(roll), -cos(yaw) * sin(roll) + sin(yaw) * sin(pitch) * cos(roll)], - [-sin(pitch), cos(pitch) * sin(roll), cos(pitch) * cos(yaw)] - ]) - - -def main(): - """ - Calculates the x, y, z coefficients for the four segments - of the trajectory - """ - x_coeffs = [[], [], [], []] - y_coeffs = [[], [], [], []] - z_coeffs = [[], [], [], []] - waypoints = [[-5, -5, 5], [5, -5, 5], [5, 5, 5], [-5, 5, 5]] - - for i in range(4): - traj = TrajectoryGenerator(waypoints[i], waypoints[(i + 1) % 4], T) - traj.solve() - x_coeffs[i] = traj.x_c - y_coeffs[i] = traj.y_c - z_coeffs[i] = traj.z_c - - quad_sim(x_coeffs, y_coeffs, z_coeffs) - - -if __name__ == "__main__": - main() diff --git a/AerialNavigation/rocket_powered_landing/rocket_powered_landing.py b/AerialNavigation/rocket_powered_landing/rocket_powered_landing.py deleted file mode 100644 index 239f3629c1b..00000000000 --- a/AerialNavigation/rocket_powered_landing/rocket_powered_landing.py +++ /dev/null @@ -1,673 +0,0 @@ -""" - -A rocket powered landing with successive convexification - -author: Sven Niederberger - Atsushi Sakai - -Ref: -- Python implementation of 'Successive Convexification for 6-DoF Mars Rocket Powered Landing with Free-Final-Time' paper -by Michael Szmuk and Behcet Acıkmese. - -- EmbersArc/SuccessiveConvexificationFreeFinalTime: Implementation of "Successive Convexification for 6-DoF Mars Rocket Powered Landing with Free-Final-Time" https://github.com/EmbersArc/SuccessiveConvexificationFreeFinalTime - -""" -import warnings -from time import time -import numpy as np -from scipy.integrate import odeint -import cvxpy -import matplotlib.pyplot as plt - -# Trajectory points -K = 50 - -# Max solver iterations -iterations = 30 - -# Weight constants -W_SIGMA = 1 # flight time -W_DELTA = 1e-3 # difference in state/input -W_DELTA_SIGMA = 1e-1 # difference in flight time -W_NU = 1e5 # virtual control - -solver = 'ECOS' -verbose_solver = False - -show_animation = True - - -class Rocket_Model_6DoF: - """ - A 6 degree of freedom rocket landing problem. - """ - - def __init__(self, rng): - """ - A large r_scale for a small scale problem will - ead to numerical problems as parameters become excessively small - and (it seems) precision is lost in the dynamics. - """ - self.n_x = 14 - self.n_u = 3 - - # Mass - self.m_wet = 3.0 # 30000 kg - self.m_dry = 2.2 # 22000 kg - - # Flight time guess - self.t_f_guess = 10.0 # 10 s - - # State constraints - self.r_I_final = np.array((0., 0., 0.)) - self.v_I_final = np.array((-1e-1, 0., 0.)) - self.q_B_I_final = self.euler_to_quat((0, 0, 0)) - self.w_B_final = np.deg2rad(np.array((0., 0., 0.))) - - self.w_B_max = np.deg2rad(60) - - # Angles - max_gimbal = 20 - max_angle = 90 - glidelslope_angle = 20 - - self.tan_delta_max = np.tan(np.deg2rad(max_gimbal)) - self.cos_theta_max = np.cos(np.deg2rad(max_angle)) - self.tan_gamma_gs = np.tan(np.deg2rad(glidelslope_angle)) - - # Thrust limits - self.T_max = 5.0 - self.T_min = 0.3 - - # Angular moment of inertia - self.J_B = 1e-2 * np.diag([1., 1., 1.]) - - # Gravity - self.g_I = np.array((-1, 0., 0.)) - - # Fuel consumption - self.alpha_m = 0.01 - - # Vector from thrust point to CoM - self.r_T_B = np.array([-1e-2, 0., 0.]) - - self.set_random_initial_state(rng) - - self.x_init = np.concatenate( - ((self.m_wet,), self.r_I_init, self.v_I_init, self.q_B_I_init, self.w_B_init)) - self.x_final = np.concatenate( - ((self.m_dry,), self.r_I_final, self.v_I_final, self.q_B_I_final, self.w_B_final)) - - self.r_scale = np.linalg.norm(self.r_I_init) - self.m_scale = self.m_wet - - def set_random_initial_state(self, rng): - if rng is None: - rng = np.random.default_rng() - - self.r_I_init = np.array((0., 0., 0.)) - self.r_I_init[0] = rng.uniform(3, 4) - self.r_I_init[1:3] = rng.uniform(-2, 2, size=2) - - self.v_I_init = np.array((0., 0., 0.)) - self.v_I_init[0] = rng.uniform(-1, -0.5) - self.v_I_init[1:3] = rng.uniform(-0.5, -0.2, - size=2) * self.r_I_init[1:3] - - self.q_B_I_init = self.euler_to_quat((0, - rng.uniform(-30, 30), - rng.uniform(-30, 30))) - self.w_B_init = np.deg2rad((0, - rng.uniform(-20, 20), - rng.uniform(-20, 20))) - - def f_func(self, x, u): - m, _, _, _, vx, vy, vz, q0, q1, q2, q3, wx, wy, wz = x[0], x[1], x[ - 2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13] - ux, uy, uz = u[0], u[1], u[2] - - return np.array([ - [-0.01 * np.sqrt(ux**2 + uy**2 + uz**2)], - [vx], - [vy], - [vz], - [(-1.0 * m - ux * (2 * q2**2 + 2 * q3**2 - 1) - 2 * uy - * (q0 * q3 - q1 * q2) + 2 * uz * (q0 * q2 + q1 * q3)) / m], - [(2 * ux * (q0 * q3 + q1 * q2) - uy * (2 * q1**2 - + 2 * q3**2 - 1) - 2 * uz * (q0 * q1 - q2 * q3)) / m], - [(-2 * ux * (q0 * q2 - q1 * q3) + 2 * uy - * (q0 * q1 + q2 * q3) - uz * (2 * q1**2 + 2 * q2**2 - 1)) / m], - [-0.5 * q1 * wx - 0.5 * q2 * wy - 0.5 * q3 * wz], - [0.5 * q0 * wx + 0.5 * q2 * wz - 0.5 * q3 * wy], - [0.5 * q0 * wy - 0.5 * q1 * wz + 0.5 * q3 * wx], - [0.5 * q0 * wz + 0.5 * q1 * wy - 0.5 * q2 * wx], - [0], - [1.0 * uz], - [-1.0 * uy] - ]) - - def A_func(self, x, u): - m, _, _, _, _, _, _, q0, q1, q2, q3, wx, wy, wz = x[0], x[1], x[ - 2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13] - ux, uy, uz = u[0], u[1], u[2] - - return np.array([ - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], - [(ux * (2 * q2**2 + 2 * q3**2 - 1) + 2 * uy * (q0 * q3 - q1 * q2) - 2 * uz * (q0 * q2 + q1 * q3)) / m**2, 0, 0, 0, 0, 0, 0, 2 * (q2 * uz - - q3 * uy) / m, 2 * (q2 * uy + q3 * uz) / m, 2 * (q0 * uz + q1 * uy - 2 * q2 * ux) / m, 2 * (-q0 * uy + q1 * uz - 2 * q3 * ux) / m, 0, 0, 0], - [(-2 * ux * (q0 * q3 + q1 * q2) + uy * (2 * q1**2 + 2 * q3**2 - 1) + 2 * uz * (q0 * q1 - q2 * q3)) / m**2, 0, 0, 0, 0, 0, 0, 2 * (-q1 * uz - + q3 * ux) / m, 2 * (-q0 * uz - 2 * q1 * uy + q2 * ux) / m, 2 * (q1 * ux + q3 * uz) / m, 2 * (q0 * ux + q2 * uz - 2 * q3 * uy) / m, 0, 0, 0], - [(2 * ux * (q0 * q2 - q1 * q3) - 2 * uy * (q0 * q1 + q2 * q3) + uz * (2 * q1**2 + 2 * q2**2 - 1)) / m**2, 0, 0, 0, 0, 0, 0, 2 * (q1 * uy - - q2 * ux) / m, 2 * (q0 * uy - 2 * q1 * uz + q3 * ux) / m, 2 * (-q0 * ux - 2 * q2 * uz + q3 * uy) / m, 2 * (q1 * ux + q2 * uy) / m, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, -0.5 * wx, -0.5 * wy, - - 0.5 * wz, -0.5 * q1, -0.5 * q2, -0.5 * q3], - [0, 0, 0, 0, 0, 0, 0, 0.5 * wx, 0, 0.5 * wz, - - 0.5 * wy, 0.5 * q0, -0.5 * q3, 0.5 * q2], - [0, 0, 0, 0, 0, 0, 0, 0.5 * wy, -0.5 * wz, 0, - 0.5 * wx, 0.5 * q3, 0.5 * q0, -0.5 * q1], - [0, 0, 0, 0, 0, 0, 0, 0.5 * wz, 0.5 * wy, - - 0.5 * wx, 0, -0.5 * q2, 0.5 * q1, 0.5 * q0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) - - def B_func(self, x, u): - m, _, _, _, _, _, _, q0, q1, q2, q3, _, _, _ = x[0], x[1], x[ - 2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13] - ux, uy, uz = u[0], u[1], u[2] - - return np.array([ - [-0.01 * ux / np.sqrt(ux**2 + uy**2 + uz**2), - -0.01 * uy / np.sqrt(ux ** 2 + uy**2 + uz**2), - -0.01 * uz / np.sqrt(ux**2 + uy**2 + uz**2)], - [0, 0, 0], - [0, 0, 0], - [0, 0, 0], - [(-2 * q2**2 - 2 * q3**2 + 1) / m, 2 - * (-q0 * q3 + q1 * q2) / m, 2 * (q0 * q2 + q1 * q3) / m], - [2 * (q0 * q3 + q1 * q2) / m, (-2 * q1**2 - 2 - * q3**2 + 1) / m, 2 * (-q0 * q1 + q2 * q3) / m], - [2 * (-q0 * q2 + q1 * q3) / m, 2 * (q0 * q1 + q2 * q3) - / m, (-2 * q1**2 - 2 * q2**2 + 1) / m], - [0, 0, 0], - [0, 0, 0], - [0, 0, 0], - [0, 0, 0], - [0, 0, 0], - [0, 0, 1.0], - [0, -1.0, 0] - ]) - - def euler_to_quat(self, a): - a = np.deg2rad(a) - - cy = np.cos(a[1] * 0.5) - sy = np.sin(a[1] * 0.5) - cr = np.cos(a[0] * 0.5) - sr = np.sin(a[0] * 0.5) - cp = np.cos(a[2] * 0.5) - sp = np.sin(a[2] * 0.5) - - q = np.zeros(4) - - q[0] = cy * cr * cp + sy * sr * sp - q[1] = cy * sr * cp - sy * cr * sp - q[3] = cy * cr * sp + sy * sr * cp - q[2] = sy * cr * cp - cy * sr * sp - - return q - - def skew(self, v): - return np.array([ - [0, -v[2], v[1]], - [v[2], 0, -v[0]], - [-v[1], v[0], 0] - ]) - - def dir_cosine(self, q): - return np.array([ - [1 - 2 * (q[2] ** 2 + q[3] ** 2), 2 * (q[1] * q[2] - + q[0] * q[3]), 2 * (q[1] * q[3] - q[0] * q[2])], - [2 * (q[1] * q[2] - q[0] * q[3]), 1 - 2 - * (q[1] ** 2 + q[3] ** 2), 2 * (q[2] * q[3] + q[0] * q[1])], - [2 * (q[1] * q[3] + q[0] * q[2]), 2 * (q[2] * q[3] - - q[0] * q[1]), 1 - 2 * (q[1] ** 2 + q[2] ** 2)] - ]) - - def omega(self, w): - return np.array([ - [0, -w[0], -w[1], -w[2]], - [w[0], 0, w[2], -w[1]], - [w[1], -w[2], 0, w[0]], - [w[2], w[1], -w[0], 0], - ]) - - def initialize_trajectory(self, X, U): - """ - Initialize the trajectory with linear approximation. - """ - K = X.shape[1] - - for k in range(K): - alpha1 = (K - k) / K - alpha2 = k / K - - m_k = (alpha1 * self.x_init[0] + alpha2 * self.x_final[0],) - r_I_k = alpha1 * self.x_init[1:4] + alpha2 * self.x_final[1:4] - v_I_k = alpha1 * self.x_init[4:7] + alpha2 * self.x_final[4:7] - q_B_I_k = np.array([1, 0, 0, 0]) - w_B_k = alpha1 * self.x_init[11:14] + alpha2 * self.x_final[11:14] - - X[:, k] = np.concatenate((m_k, r_I_k, v_I_k, q_B_I_k, w_B_k)) - U[:, k] = m_k * -self.g_I - - return X, U - - def get_constraints(self, X_v, U_v, X_last_p, U_last_p): - """ - Get model specific constraints. - - :param X_v: cvx variable for current states - :param U_v: cvx variable for current inputs - :param X_last_p: cvx parameter for last states - :param U_last_p: cvx parameter for last inputs - :return: A list of cvx constraints - """ - # Boundary conditions: - constraints = [ - X_v[0, 0] == self.x_init[0], - X_v[1:4, 0] == self.x_init[1:4], - X_v[4:7, 0] == self.x_init[4:7], - # X_v[7:11, 0] == self.x_init[7:11], # initial orientation is free - X_v[11:14, 0] == self.x_init[11:14], - - # X_[0, -1] final mass is free - X_v[1:, -1] == self.x_final[1:], - U_v[1:3, -1] == 0, - ] - - constraints += [ - # State constraints: - X_v[0, :] >= self.m_dry, # minimum mass - cvxpy.norm(X_v[2: 4, :], axis=0) <= X_v[1, :] / \ - self.tan_gamma_gs, # glideslope - cvxpy.norm(X_v[9:11, :], axis=0) <= np.sqrt( - (1 - self.cos_theta_max) / 2), # maximum angle - # maximum angular velocity - cvxpy.norm(X_v[11: 14, :], axis=0) <= self.w_B_max, - - # Control constraints: - cvxpy.norm(U_v[1:3, :], axis=0) <= self.tan_delta_max * \ - U_v[0, :], # gimbal angle constraint - cvxpy.norm(U_v, axis=0) <= self.T_max, # upper thrust constraint - ] - - # linearized lower thrust constraint - rhs = [U_last_p[:, k] / cvxpy.norm(U_last_p[:, k]) @ U_v[:, k] - for k in range(X_v.shape[1])] - constraints += [ - self.T_min <= cvxpy.vstack(rhs) - ] - - return constraints - - -class Integrator: - def __init__(self, m, K): - self.K = K - self.m = m - self.n_x = m.n_x - self.n_u = m.n_u - - self.A_bar = np.zeros([m.n_x * m.n_x, K - 1]) - self.B_bar = np.zeros([m.n_x * m.n_u, K - 1]) - self.C_bar = np.zeros([m.n_x * m.n_u, K - 1]) - self.S_bar = np.zeros([m.n_x, K - 1]) - self.z_bar = np.zeros([m.n_x, K - 1]) - - # vector indices for flat matrices - x_end = m.n_x - A_bar_end = m.n_x * (1 + m.n_x) - B_bar_end = m.n_x * (1 + m.n_x + m.n_u) - C_bar_end = m.n_x * (1 + m.n_x + m.n_u + m.n_u) - S_bar_end = m.n_x * (1 + m.n_x + m.n_u + m.n_u + 1) - z_bar_end = m.n_x * (1 + m.n_x + m.n_u + m.n_u + 2) - self.x_ind = slice(0, x_end) - self.A_bar_ind = slice(x_end, A_bar_end) - self.B_bar_ind = slice(A_bar_end, B_bar_end) - self.C_bar_ind = slice(B_bar_end, C_bar_end) - self.S_bar_ind = slice(C_bar_end, S_bar_end) - self.z_bar_ind = slice(S_bar_end, z_bar_end) - - self.f, self.A, self.B = m.f_func, m.A_func, m.B_func - - # integration initial condition - self.V0 = np.zeros((m.n_x * (1 + m.n_x + m.n_u + m.n_u + 2),)) - self.V0[self.A_bar_ind] = np.eye(m.n_x).reshape(-1) - - self.dt = 1. / (K - 1) - - def calculate_discretization(self, X, U, sigma): - """ - Calculate discretization for given states, inputs and total time. - - :param X: Matrix of states for all time points - :param U: Matrix of inputs for all time points - :param sigma: Total time - :return: The discretization matrices - """ - for k in range(self.K - 1): - self.V0[self.x_ind] = X[:, k] - V = np.array(odeint(self._ode_dVdt, self.V0, (0, self.dt), - args=(U[:, k], U[:, k + 1], sigma))[1, :]) - - # using \Phi_A(\tau_{k+1},\xi) = \Phi_A(\tau_{k+1},\tau_k)\Phi_A(\xi,\tau_k)^{-1} - # flatten matrices in column-major (Fortran) order for CVXPY - Phi = V[self.A_bar_ind].reshape((self.n_x, self.n_x)) - self.A_bar[:, k] = Phi.flatten(order='F') - self.B_bar[:, k] = np.matmul(Phi, V[self.B_bar_ind].reshape( - (self.n_x, self.n_u))).flatten(order='F') - self.C_bar[:, k] = np.matmul(Phi, V[self.C_bar_ind].reshape( - (self.n_x, self.n_u))).flatten(order='F') - self.S_bar[:, k] = np.matmul(Phi, V[self.S_bar_ind]) - self.z_bar[:, k] = np.matmul(Phi, V[self.z_bar_ind]) - - return self.A_bar, self.B_bar, self.C_bar, self.S_bar, self.z_bar - - def _ode_dVdt(self, V, t, u_t0, u_t1, sigma): - """ - ODE function to compute dVdt. - - :param V: Evaluation state V = [x, Phi_A, B_bar, C_bar, S_bar, z_bar] - :param t: Evaluation time - :param u_t0: Input at start of interval - :param u_t1: Input at end of interval - :param sigma: Total time - :return: Derivative at current time and state dVdt - """ - alpha = (self.dt - t) / self.dt - beta = t / self.dt - x = V[self.x_ind] - u = u_t0 + beta * (u_t1 - u_t0) - - # using \Phi_A(\tau_{k+1},\xi) = \Phi_A(\tau_{k+1},\tau_k)\Phi_A(\xi,\tau_k)^{-1} - # and pre-multiplying with \Phi_A(\tau_{k+1},\tau_k) after integration - Phi_A_xi = np.linalg.inv( - V[self.A_bar_ind].reshape((self.n_x, self.n_x))) - - A_subs = sigma * self.A(x, u) - B_subs = sigma * self.B(x, u) - f_subs = self.f(x, u) - - dVdt = np.zeros_like(V) - dVdt[self.x_ind] = sigma * f_subs.transpose() - dVdt[self.A_bar_ind] = np.matmul( - A_subs, V[self.A_bar_ind].reshape((self.n_x, self.n_x))).reshape(-1) - dVdt[self.B_bar_ind] = np.matmul(Phi_A_xi, B_subs).reshape(-1) * alpha - dVdt[self.C_bar_ind] = np.matmul(Phi_A_xi, B_subs).reshape(-1) * beta - dVdt[self.S_bar_ind] = np.matmul(Phi_A_xi, f_subs).transpose() - z_t = -np.matmul(A_subs, x) - np.matmul(B_subs, u) - dVdt[self.z_bar_ind] = np.dot(Phi_A_xi, z_t.T).flatten() - - return dVdt - - -class SCProblem: - """ - Defines a standard Successive Convexification problem and - adds the model specific constraints and objectives. - - :param m: The model object - :param K: Number of discretization points - """ - - def __init__(self, m, K): - # Variables: - self.var = dict() - self.var['X'] = cvxpy.Variable((m.n_x, K)) - self.var['U'] = cvxpy.Variable((m.n_u, K)) - self.var['sigma'] = cvxpy.Variable(nonneg=True) - self.var['nu'] = cvxpy.Variable((m.n_x, K - 1)) - self.var['delta_norm'] = cvxpy.Variable(nonneg=True) - self.var['sigma_norm'] = cvxpy.Variable(nonneg=True) - - # Parameters: - self.par = dict() - self.par['A_bar'] = cvxpy.Parameter((m.n_x * m.n_x, K - 1)) - self.par['B_bar'] = cvxpy.Parameter((m.n_x * m.n_u, K - 1)) - self.par['C_bar'] = cvxpy.Parameter((m.n_x * m.n_u, K - 1)) - self.par['S_bar'] = cvxpy.Parameter((m.n_x, K - 1)) - self.par['z_bar'] = cvxpy.Parameter((m.n_x, K - 1)) - - self.par['X_last'] = cvxpy.Parameter((m.n_x, K)) - self.par['U_last'] = cvxpy.Parameter((m.n_u, K)) - self.par['sigma_last'] = cvxpy.Parameter(nonneg=True) - - self.par['weight_sigma'] = cvxpy.Parameter(nonneg=True) - self.par['weight_delta'] = cvxpy.Parameter(nonneg=True) - self.par['weight_delta_sigma'] = cvxpy.Parameter(nonneg=True) - self.par['weight_nu'] = cvxpy.Parameter(nonneg=True) - - # Constraints: - constraints = [] - - # Model: - constraints += m.get_constraints( - self.var['X'], self.var['U'], self.par['X_last'], self.par['U_last']) - - # Dynamics: - # x_t+1 = A_*x_t+B_*U_t+C_*U_T+1*S_*sigma+zbar+nu - constraints += [ - self.var['X'][:, k + 1] == - cvxpy.reshape(self.par['A_bar'][:, k], (m.n_x, m.n_x)) @ - self.var['X'][:, k] + - cvxpy.reshape(self.par['B_bar'][:, k], (m.n_x, m.n_u)) @ - self.var['U'][:, k] + - cvxpy.reshape(self.par['C_bar'][:, k], (m.n_x, m.n_u)) @ - self.var['U'][:, k + 1] + - self.par['S_bar'][:, k] * self.var['sigma'] + - self.par['z_bar'][:, k] + - self.var['nu'][:, k] - for k in range(K - 1) - ] - - # Trust regions: - dx = cvxpy.sum(cvxpy.square( - self.var['X'] - self.par['X_last']), axis=0) - du = cvxpy.sum(cvxpy.square( - self.var['U'] - self.par['U_last']), axis=0) - ds = self.var['sigma'] - self.par['sigma_last'] - constraints += [cvxpy.norm(dx + du, 1) <= self.var['delta_norm']] - constraints += [cvxpy.norm(ds, 'inf') <= self.var['sigma_norm']] - - # Flight time positive: - constraints += [self.var['sigma'] >= 0.1] - - # Objective: - sc_objective = cvxpy.Minimize( - self.par['weight_sigma'] * self.var['sigma'] + - self.par['weight_nu'] * cvxpy.norm(self.var['nu'], 'inf') + - self.par['weight_delta'] * self.var['delta_norm'] + - self.par['weight_delta_sigma'] * self.var['sigma_norm'] - ) - - objective = sc_objective - - self.prob = cvxpy.Problem(objective, constraints) - - def set_parameters(self, **kwargs): - """ - All parameters have to be filled before calling solve(). - Takes the following arguments as keywords: - - A_bar - B_bar - C_bar - S_bar - z_bar - X_last - U_last - sigma_last - E - weight_sigma - weight_nu - radius_trust_region - """ - - for key in kwargs: - if key in self.par: - self.par[key].value = kwargs[key] - else: - print(f'Parameter \'{key}\' does not exist.') - - def get_variable(self, name): - if name in self.var: - return self.var[name].value - else: - print(f'Variable \'{name}\' does not exist.') - return None - - def solve(self, **kwargs): - error = False - try: - with warnings.catch_warnings(): # For User warning from solver - warnings.simplefilter('ignore') - self.prob.solve(verbose=verbose_solver, - solver=solver) - except cvxpy.SolverError: - error = True - - stats = self.prob.solver_stats - - info = { - 'setup_time': stats.setup_time, - 'solver_time': stats.solve_time, - 'iterations': stats.num_iters, - 'solver_error': error - } - - return info - - -def axis3d_equal(X, Y, Z, ax): - - max_range = np.array([X.max() - X.min(), Y.max() - - Y.min(), Z.max() - Z.min()]).max() - Xb = 0.5 * max_range * np.mgrid[-1:2:2, -1:2:2, - - 1:2:2][0].flatten() + 0.5 * (X.max() + X.min()) - Yb = 0.5 * max_range * np.mgrid[-1:2:2, -1:2:2, - - 1:2:2][1].flatten() + 0.5 * (Y.max() + Y.min()) - Zb = 0.5 * max_range * np.mgrid[-1:2:2, -1:2:2, - - 1:2:2][2].flatten() + 0.5 * (Z.max() + Z.min()) - # Comment or uncomment following both lines to test the fake bounding box: - for xb, yb, zb in zip(Xb, Yb, Zb): - ax.plot([xb], [yb], [zb], 'w') - - -def plot_animation(X, U): # pragma: no cover - - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - # for stopping simulation with the esc key. - fig.canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - for k in range(K): - plt.cla() - ax.plot(X[2, :], X[3, :], X[1, :]) # trajectory - ax.scatter3D([0.0], [0.0], [0.0], c="r", - marker="x") # target landing point - axis3d_equal(X[2, :], X[3, :], X[1, :], ax) - - rx, ry, rz = X[1:4, k] - # vx, vy, vz = X[4:7, k] - qw, qx, qy, qz = X[7:11, k] - - CBI = np.array([ - [1 - 2 * (qy ** 2 + qz ** 2), 2 * (qx * qy + qw * qz), - 2 * (qx * qz - qw * qy)], - [2 * (qx * qy - qw * qz), 1 - 2 - * (qx ** 2 + qz ** 2), 2 * (qy * qz + qw * qx)], - [2 * (qx * qz + qw * qy), 2 * (qy * qz - qw * qx), - 1 - 2 * (qx ** 2 + qy ** 2)] - ]) - - Fx, Fy, Fz = np.dot(np.transpose(CBI), U[:, k]) - dx, dy, dz = np.dot(np.transpose(CBI), np.array([1., 0., 0.])) - - # attitude vector - ax.quiver(ry, rz, rx, dy, dz, dx, length=0.5, linewidth=3.0, - arrow_length_ratio=0.0, color='black') - - # thrust vector - ax.quiver(ry, rz, rx, -Fy, -Fz, -Fx, length=0.1, - arrow_length_ratio=0.0, color='red') - - ax.set_title("Rocket powered landing") - plt.pause(0.5) - - -def main(rng=None): - print("start!!") - m = Rocket_Model_6DoF(rng) - - # state and input list - X = np.empty(shape=[m.n_x, K]) - U = np.empty(shape=[m.n_u, K]) - - # INITIALIZATION - sigma = m.t_f_guess - X, U = m.initialize_trajectory(X, U) - - integrator = Integrator(m, K) - problem = SCProblem(m, K) - - converged = False - w_delta = W_DELTA - for it in range(iterations): - t0_it = time() - print('-' * 18 + f' Iteration {str(it + 1).zfill(2)} ' + '-' * 18) - - A_bar, B_bar, C_bar, S_bar, z_bar = integrator.calculate_discretization( - X, U, sigma) - - problem.set_parameters(A_bar=A_bar, B_bar=B_bar, C_bar=C_bar, S_bar=S_bar, z_bar=z_bar, - X_last=X, U_last=U, sigma_last=sigma, - weight_sigma=W_SIGMA, weight_nu=W_NU, - weight_delta=w_delta, weight_delta_sigma=W_DELTA_SIGMA) - problem.solve() - - X = problem.get_variable('X') - U = problem.get_variable('U') - sigma = problem.get_variable('sigma') - - delta_norm = problem.get_variable('delta_norm') - sigma_norm = problem.get_variable('sigma_norm') - nu_norm = np.linalg.norm(problem.get_variable('nu'), np.inf) - - print('delta_norm', delta_norm) - print('sigma_norm', sigma_norm) - print('nu_norm', nu_norm) - - if delta_norm < 1e-3 and sigma_norm < 1e-3 and nu_norm < 1e-7: - converged = True - - w_delta *= 1.5 - - print('Time for iteration', time() - t0_it, 's') - - if converged: - print(f'Converged after {it + 1} iterations.') - break - - if show_animation: # pragma: no cover - plot_animation(X, U) - - print("done!!") - - -if __name__ == '__main__': - main() diff --git a/ArmNavigation/__init__.py b/ArmNavigation/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation.py b/ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation.py deleted file mode 100644 index 9047c138514..00000000000 --- a/ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation.py +++ /dev/null @@ -1,268 +0,0 @@ -""" -Obstacle navigation using A* on a toroidal grid - -Author: Daniel Ingram (daniel-s-ingram) -""" -from math import pi -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.colors import from_levels_and_colors - -plt.ion() - -# Simulation parameters -M = 100 -obstacles = [[1.75, 0.75, 0.6], [0.55, 1.5, 0.5], [0, -1, 0.25]] - - -def main(): - arm = NLinkArm([1, 1], [0, 0]) - start = (10, 50) - goal = (58, 56) - grid = get_occupancy_grid(arm, obstacles) - plt.imshow(grid) - plt.show() - route = astar_torus(grid, start, goal) - for node in route: - theta1 = 2 * pi * node[0] / M - pi - theta2 = 2 * pi * node[1] / M - pi - arm.update_joints([theta1, theta2]) - arm.plot(obstacles=obstacles) - - -def detect_collision(line_seg, circle): - """ - Determines whether a line segment (arm link) is in contact - with a circle (obstacle). - Credit to: https://web.archive.org/web/20200130224918/http://doswa.com/2009/07/13/circle-segment-intersectioncollision.html - Args: - line_seg: List of coordinates of line segment endpoints e.g. [[1, 1], [2, 2]] - circle: List of circle coordinates and radius e.g. [0, 0, 0.5] is a circle centered - at the origin with radius 0.5 - - Returns: - True if the line segment is in contact with the circle - False otherwise - """ - a_vec = np.array([line_seg[0][0], line_seg[0][1]]) - b_vec = np.array([line_seg[1][0], line_seg[1][1]]) - c_vec = np.array([circle[0], circle[1]]) - radius = circle[2] - line_vec = b_vec - a_vec - line_mag = np.linalg.norm(line_vec) - circle_vec = c_vec - a_vec - proj = circle_vec.dot(line_vec / line_mag) - if proj <= 0: - closest_point = a_vec - elif proj >= line_mag: - closest_point = b_vec - else: - closest_point = a_vec + line_vec * proj / line_mag - if np.linalg.norm(closest_point - c_vec) > radius: - return False - - return True - - -def get_occupancy_grid(arm, obstacles): - """ - Discretizes joint space into M values from -pi to +pi - and determines whether a given coordinate in joint space - would result in a collision between a robot arm and obstacles - in its environment. - - Args: - arm: An instance of NLinkArm - obstacles: A list of obstacles, with each obstacle defined as a list - of xy coordinates and a radius. - - Returns: - Occupancy grid in joint space - """ - grid = [[0 for _ in range(M)] for _ in range(M)] - theta_list = [2 * i * pi / M for i in range(-M // 2, M // 2 + 1)] - for i in range(M): - for j in range(M): - arm.update_joints([theta_list[i], theta_list[j]]) - points = arm.points - collision_detected = False - for k in range(len(points) - 1): - for obstacle in obstacles: - line_seg = [points[k], points[k + 1]] - collision_detected = detect_collision(line_seg, obstacle) - if collision_detected: - break - if collision_detected: - break - grid[i][j] = int(collision_detected) - return np.array(grid) - - -def astar_torus(grid, start_node, goal_node): - """ - Finds a path between an initial and goal joint configuration using - the A* Algorithm on a tororiadal grid. - - Args: - grid: An occupancy grid (ndarray) - start_node: Initial joint configuration (tuple) - goal_node: Goal joint configuration (tuple) - - Returns: - Obstacle-free route in joint space from start_node to goal_node - """ - colors = ['white', 'black', 'red', 'pink', 'yellow', 'green', 'orange'] - levels = [0, 1, 2, 3, 4, 5, 6, 7] - cmap, norm = from_levels_and_colors(levels, colors) - - grid[start_node] = 4 - grid[goal_node] = 5 - - parent_map = [[() for _ in range(M)] for _ in range(M)] - - heuristic_map = calc_heuristic_map(M, goal_node) - - explored_heuristic_map = np.full((M, M), np.inf) - distance_map = np.full((M, M), np.inf) - explored_heuristic_map[start_node] = heuristic_map[start_node] - distance_map[start_node] = 0 - while True: - grid[start_node] = 4 - grid[goal_node] = 5 - - current_node = np.unravel_index( - np.argmin(explored_heuristic_map, axis=None), explored_heuristic_map.shape) - min_distance = np.min(explored_heuristic_map) - if (current_node == goal_node) or np.isinf(min_distance): - break - - grid[current_node] = 2 - explored_heuristic_map[current_node] = np.inf - - i, j = current_node[0], current_node[1] - - neighbors = find_neighbors(i, j) - - for neighbor in neighbors: - if grid[neighbor] == 0 or grid[neighbor] == 5: - distance_map[neighbor] = distance_map[current_node] + 1 - explored_heuristic_map[neighbor] = heuristic_map[neighbor] - parent_map[neighbor[0]][neighbor[1]] = current_node - grid[neighbor] = 3 - - if np.isinf(explored_heuristic_map[goal_node]): - route = [] - print("No route found.") - else: - route = [goal_node] - while parent_map[route[0][0]][route[0][1]] != (): - route.insert(0, parent_map[route[0][0]][route[0][1]]) - - print(f"The route found covers {len(route)} grid cells.") - for i in range(1, len(route)): - grid[route[i]] = 6 - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.imshow(grid, cmap=cmap, norm=norm, interpolation=None) - plt.show() - plt.pause(1e-2) - - return route - - -def find_neighbors(i, j): - neighbors = [] - if i - 1 >= 0: - neighbors.append((i - 1, j)) - else: - neighbors.append((M - 1, j)) - - if i + 1 < M: - neighbors.append((i + 1, j)) - else: - neighbors.append((0, j)) - - if j - 1 >= 0: - neighbors.append((i, j - 1)) - else: - neighbors.append((i, M - 1)) - - if j + 1 < M: - neighbors.append((i, j + 1)) - else: - neighbors.append((i, 0)) - - return neighbors - - -def calc_heuristic_map(M, goal_node): - X, Y = np.meshgrid([i for i in range(M)], [i for i in range(M)]) - heuristic_map = np.abs(X - goal_node[1]) + np.abs(Y - goal_node[0]) - for i in range(heuristic_map.shape[0]): - for j in range(heuristic_map.shape[1]): - heuristic_map[i, j] = min(heuristic_map[i, j], - M - i - 1 + heuristic_map[M - 1, j], - i + heuristic_map[0, j], - M - j - 1 + heuristic_map[i, M - 1], - j + heuristic_map[i, 0] - ) - - return heuristic_map - - -class NLinkArm: - """ - Class for controlling and plotting a planar arm with an arbitrary number of links. - """ - - def __init__(self, link_lengths, joint_angles): - self.n_links = len(link_lengths) - if self.n_links != len(joint_angles): - raise ValueError() - - self.link_lengths = np.array(link_lengths) - self.joint_angles = np.array(joint_angles) - self.points = [[0, 0] for _ in range(self.n_links + 1)] - - self.lim = sum(link_lengths) - self.update_points() - - def update_joints(self, joint_angles): - self.joint_angles = joint_angles - self.update_points() - - def update_points(self): - for i in range(1, self.n_links + 1): - self.points[i][0] = self.points[i - 1][0] + \ - self.link_lengths[i - 1] * \ - np.cos(np.sum(self.joint_angles[:i])) - self.points[i][1] = self.points[i - 1][1] + \ - self.link_lengths[i - 1] * \ - np.sin(np.sum(self.joint_angles[:i])) - - self.end_effector = np.array(self.points[self.n_links]).T - - def plot(self, obstacles=[]): # pragma: no cover - plt.cla() - - for obstacle in obstacles: - circle = plt.Circle( - (obstacle[0], obstacle[1]), radius=0.5 * obstacle[2], fc='k') - plt.gca().add_patch(circle) - - for i in range(self.n_links + 1): - if i is not self.n_links: - plt.plot([self.points[i][0], self.points[i + 1][0]], - [self.points[i][1], self.points[i + 1][1]], 'r-') - plt.plot(self.points[i][0], self.points[i][1], 'k.') - - plt.xlim([-self.lim, self.lim]) - plt.ylim([-self.lim, self.lim]) - plt.draw() - plt.pause(1e-5) - - -if __name__ == '__main__': - main() diff --git a/ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation_2.py b/ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation_2.py deleted file mode 100644 index f5d435082a5..00000000000 --- a/ArmNavigation/arm_obstacle_navigation/arm_obstacle_navigation_2.py +++ /dev/null @@ -1,299 +0,0 @@ -""" -Obstacle navigation using A* on a toroidal grid - -Author: Daniel Ingram (daniel-s-ingram) - Tullio Facchinetti (tullio.facchinetti@unipv.it) -""" -from math import pi -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.colors import from_levels_and_colors -import sys - -plt.ion() - -# Simulation parameters -M = 100 -obstacles = [[1.75, 0.75, 0.6], [0.55, 1.5, 0.5], [0, -1, 0.7]] - - -def press(event): - """Exit from the simulation.""" - if event.key == 'q' or event.key == 'Q': - print('Quitting upon request.') - sys.exit(0) - - -def main(): - # Arm geometry in the working space - link_length = [0.5, 1.5] - initial_link_angle = [0, 0] - arm = NLinkArm(link_length, initial_link_angle) - # (x, y) co-ordinates in the joint space [cell] - start = (10, 50) - goal = (58, 56) - grid = get_occupancy_grid(arm, obstacles) - route = astar_torus(grid, start, goal) - if route: - animate(grid, arm, route) - - -def animate(grid, arm, route): - fig, axs = plt.subplots(1, 2) - fig.canvas.mpl_connect('key_press_event', press) - colors = ['white', 'black', 'red', 'pink', 'yellow', 'green', 'orange'] - levels = [0, 1, 2, 3, 4, 5, 6, 7] - cmap, norm = from_levels_and_colors(levels, colors) - for i, node in enumerate(route): - plt.subplot(1, 2, 1) - grid[node] = 6 - plt.cla() - plt.imshow(grid, cmap=cmap, norm=norm, interpolation=None) - theta1 = 2 * pi * node[0] / M - pi - theta2 = 2 * pi * node[1] / M - pi - arm.update_joints([theta1, theta2]) - plt.subplot(1, 2, 2) - arm.plot_arm(plt, obstacles=obstacles) - plt.xlim(-2.0, 2.0) - plt.ylim(-3.0, 3.0) - plt.show() - # Uncomment here to save the sequence of frames - # plt.savefig('frame{:04d}.png'.format(i)) - plt.pause(0.1) - - -def detect_collision(line_seg, circle): - """ - Determines whether a line segment (arm link) is in contact - with a circle (obstacle). - Credit to: https://web.archive.org/web/20200130224918/http://doswa.com/2009/07/13/circle-segment-intersectioncollision.html - Args: - line_seg: List of coordinates of line segment endpoints e.g. [[1, 1], [2, 2]] - circle: List of circle coordinates and radius e.g. [0, 0, 0.5] is a circle centered - at the origin with radius 0.5 - - Returns: - True if the line segment is in contact with the circle - False otherwise - """ - a_vec = np.array([line_seg[0][0], line_seg[0][1]]) - b_vec = np.array([line_seg[1][0], line_seg[1][1]]) - c_vec = np.array([circle[0], circle[1]]) - radius = circle[2] - line_vec = b_vec - a_vec - line_mag = np.linalg.norm(line_vec) - circle_vec = c_vec - a_vec - proj = circle_vec.dot(line_vec / line_mag) - if proj <= 0: - closest_point = a_vec - elif proj >= line_mag: - closest_point = b_vec - else: - closest_point = a_vec + line_vec * proj / line_mag - if np.linalg.norm(closest_point - c_vec) > radius: - return False - return True - - -def get_occupancy_grid(arm, obstacles): - """ - Discretizes joint space into M values from -pi to +pi - and determines whether a given coordinate in joint space - would result in a collision between a robot arm and obstacles - in its environment. - - Args: - arm: An instance of NLinkArm - obstacles: A list of obstacles, with each obstacle defined as a list - of xy coordinates and a radius. - - Returns: - Occupancy grid in joint space - """ - grid = [[0 for _ in range(M)] for _ in range(M)] - theta_list = [2 * i * pi / M for i in range(-M // 2, M // 2 + 1)] - for i in range(M): - for j in range(M): - arm.update_joints([theta_list[i], theta_list[j]]) - points = arm.points - collision_detected = False - for k in range(len(points) - 1): - for obstacle in obstacles: - line_seg = [points[k], points[k + 1]] - collision_detected = detect_collision(line_seg, obstacle) - if collision_detected: - break - if collision_detected: - break - grid[i][j] = int(collision_detected) - return np.array(grid) - - -def astar_torus(grid, start_node, goal_node): - """ - Finds a path between an initial and goal joint configuration using - the A* Algorithm on a tororiadal grid. - - Args: - grid: An occupancy grid (ndarray) - start_node: Initial joint configuration (tuple) - goal_node: Goal joint configuration (tuple) - - Returns: - Obstacle-free route in joint space from start_node to goal_node - """ - colors = ['white', 'black', 'red', 'pink', 'yellow', 'green', 'orange'] - levels = [0, 1, 2, 3, 4, 5, 6, 7] - cmap, norm = from_levels_and_colors(levels, colors) - - grid[start_node] = 4 - grid[goal_node] = 5 - - parent_map = [[() for _ in range(M)] for _ in range(M)] - - heuristic_map = calc_heuristic_map(M, goal_node) - - explored_heuristic_map = np.full((M, M), np.inf) - distance_map = np.full((M, M), np.inf) - explored_heuristic_map[start_node] = heuristic_map[start_node] - distance_map[start_node] = 0 - while True: - grid[start_node] = 4 - grid[goal_node] = 5 - - current_node = np.unravel_index( - np.argmin(explored_heuristic_map, axis=None), explored_heuristic_map.shape) - min_distance = np.min(explored_heuristic_map) - if (current_node == goal_node) or np.isinf(min_distance): - break - - grid[current_node] = 2 - explored_heuristic_map[current_node] = np.inf - - i, j = current_node[0], current_node[1] - - neighbors = find_neighbors(i, j) - - for neighbor in neighbors: - if grid[neighbor] == 0 or grid[neighbor] == 5: - distance_map[neighbor] = distance_map[current_node] + 1 - explored_heuristic_map[neighbor] = heuristic_map[neighbor] - parent_map[neighbor[0]][neighbor[1]] = current_node - grid[neighbor] = 3 - - if np.isinf(explored_heuristic_map[goal_node]): - route = [] - print("No route found.") - else: - route = [goal_node] - while parent_map[route[0][0]][route[0][1]] != (): - route.insert(0, parent_map[route[0][0]][route[0][1]]) - - print(f"The route found covers {len(route)} grid cells.") - for i in range(1, len(route)): - grid[route[i]] = 6 - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.imshow(grid, cmap=cmap, norm=norm, interpolation=None) - plt.show() - plt.pause(1e-2) - - return route - - -def find_neighbors(i, j): - neighbors = [] - if i - 1 >= 0: - neighbors.append((i - 1, j)) - else: - neighbors.append((M - 1, j)) - - if i + 1 < M: - neighbors.append((i + 1, j)) - else: - neighbors.append((0, j)) - - if j - 1 >= 0: - neighbors.append((i, j - 1)) - else: - neighbors.append((i, M - 1)) - - if j + 1 < M: - neighbors.append((i, j + 1)) - else: - neighbors.append((i, 0)) - - return neighbors - - -def calc_heuristic_map(M, goal_node): - X, Y = np.meshgrid([i for i in range(M)], [i for i in range(M)]) - heuristic_map = np.abs(X - goal_node[1]) + np.abs(Y - goal_node[0]) - for i in range(heuristic_map.shape[0]): - for j in range(heuristic_map.shape[1]): - heuristic_map[i, j] = min(heuristic_map[i, j], - M - i - 1 + heuristic_map[M - 1, j], - i + heuristic_map[0, j], - M - j - 1 + heuristic_map[i, M - 1], - j + heuristic_map[i, 0] - ) - - return heuristic_map - - -class NLinkArm: - """ - Class for controlling and plotting a planar arm with an arbitrary number of links. - """ - - def __init__(self, link_lengths, joint_angles): - self.n_links = len(link_lengths) - if self.n_links != len(joint_angles): - raise ValueError() - - self.link_lengths = np.array(link_lengths) - self.joint_angles = np.array(joint_angles) - self.points = [[0, 0] for _ in range(self.n_links + 1)] - - self.lim = sum(link_lengths) - self.update_points() - - def update_joints(self, joint_angles): - self.joint_angles = joint_angles - self.update_points() - - def update_points(self): - for i in range(1, self.n_links + 1): - self.points[i][0] = self.points[i - 1][0] + \ - self.link_lengths[i - 1] * \ - np.cos(np.sum(self.joint_angles[:i])) - self.points[i][1] = self.points[i - 1][1] + \ - self.link_lengths[i - 1] * \ - np.sin(np.sum(self.joint_angles[:i])) - - self.end_effector = np.array(self.points[self.n_links]).T - - def plot_arm(self, myplt, obstacles=[]): # pragma: no cover - myplt.cla() - - for obstacle in obstacles: - circle = myplt.Circle( - (obstacle[0], obstacle[1]), radius=0.5 * obstacle[2], fc='k') - myplt.gca().add_patch(circle) - - for i in range(self.n_links + 1): - if i is not self.n_links: - myplt.plot([self.points[i][0], self.points[i + 1][0]], - [self.points[i][1], self.points[i + 1][1]], 'r-') - myplt.plot(self.points[i][0], self.points[i][1], 'k.') - - myplt.xlim([-self.lim, self.lim]) - myplt.ylim([-self.lim, self.lim]) - myplt.draw() - # myplt.pause(1e-5) - - -if __name__ == '__main__': - main() diff --git a/ArmNavigation/n_joint_arm_3d/NLinkArm3d.py b/ArmNavigation/n_joint_arm_3d/NLinkArm3d.py deleted file mode 100644 index 0459e234b20..00000000000 --- a/ArmNavigation/n_joint_arm_3d/NLinkArm3d.py +++ /dev/null @@ -1,215 +0,0 @@ -""" -Class of n-link arm in 3D -Author: Takayuki Murooka (takayuki5168) -""" -import numpy as np -import math -from mpl_toolkits.mplot3d import Axes3D -import matplotlib.pyplot as plt - - -class Link: - def __init__(self, dh_params): - self.dh_params_ = dh_params - - def transformation_matrix(self): - theta = self.dh_params_[0] - alpha = self.dh_params_[1] - a = self.dh_params_[2] - d = self.dh_params_[3] - - st = math.sin(theta) - ct = math.cos(theta) - sa = math.sin(alpha) - ca = math.cos(alpha) - trans = np.array([[ct, -st * ca, st * sa, a * ct], - [st, ct * ca, -ct * sa, a * st], - [0, sa, ca, d], - [0, 0, 0, 1]]) - - return trans - - @staticmethod - def basic_jacobian(trans_prev, ee_pos): - pos_prev = np.array( - [trans_prev[0, 3], trans_prev[1, 3], trans_prev[2, 3]]) - z_axis_prev = np.array( - [trans_prev[0, 2], trans_prev[1, 2], trans_prev[2, 2]]) - - basic_jacobian = np.hstack( - (np.cross(z_axis_prev, ee_pos - pos_prev), z_axis_prev)) - return basic_jacobian - - -class NLinkArm: - def __init__(self, dh_params_list): - self.link_list = [] - for i in range(len(dh_params_list)): - self.link_list.append(Link(dh_params_list[i])) - - def transformation_matrix(self): - trans = np.identity(4) - for i in range(len(self.link_list)): - trans = np.dot(trans, self.link_list[i].transformation_matrix()) - return trans - - def forward_kinematics(self, plot=False): - trans = self.transformation_matrix() - - x = trans[0, 3] - y = trans[1, 3] - z = trans[2, 3] - alpha, beta, gamma = self.euler_angle() - - if plot: - self.fig = plt.figure() - self.ax = Axes3D(self.fig, auto_add_to_figure=False) - self.fig.add_axes(self.ax) - - x_list = [] - y_list = [] - z_list = [] - - trans = np.identity(4) - - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - for i in range(len(self.link_list)): - trans = np.dot(trans, self.link_list[i].transformation_matrix()) - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - - self.ax.plot(x_list, y_list, z_list, "o-", color="#00aa00", ms=4, - mew=0.5) - self.ax.plot([0], [0], [0], "o") - - self.ax.set_xlim(-1, 1) - self.ax.set_ylim(-1, 1) - self.ax.set_zlim(-1, 1) - - plt.show() - - return [x, y, z, alpha, beta, gamma] - - def basic_jacobian(self): - ee_pos = self.forward_kinematics()[0:3] - basic_jacobian_mat = [] - - trans = np.identity(4) - for i in range(len(self.link_list)): - basic_jacobian_mat.append( - self.link_list[i].basic_jacobian(trans, ee_pos)) - trans = np.dot(trans, self.link_list[i].transformation_matrix()) - - return np.array(basic_jacobian_mat).T - - def inverse_kinematics(self, ref_ee_pose, plot=False): - for cnt in range(500): - ee_pose = self.forward_kinematics() - diff_pose = np.array(ref_ee_pose) - ee_pose - - basic_jacobian_mat = self.basic_jacobian() - alpha, beta, gamma = self.euler_angle() - - K_zyz = np.array( - [[0, -math.sin(alpha), math.cos(alpha) * math.sin(beta)], - [0, math.cos(alpha), math.sin(alpha) * math.sin(beta)], - [1, 0, math.cos(beta)]]) - K_alpha = np.identity(6) - K_alpha[3:, 3:] = K_zyz - - theta_dot = np.dot( - np.dot(np.linalg.pinv(basic_jacobian_mat), K_alpha), - np.array(diff_pose)) - self.update_joint_angles(theta_dot / 100.) - - if plot: - self.fig = plt.figure() - self.ax = Axes3D(self.fig, auto_add_to_figure=False) - self.fig.add_axes(self.ax) - - x_list = [] - y_list = [] - z_list = [] - - trans = np.identity(4) - - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - for i in range(len(self.link_list)): - trans = np.dot(trans, self.link_list[i].transformation_matrix()) - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - - self.ax.plot(x_list, y_list, z_list, "o-", color="#00aa00", ms=4, - mew=0.5) - self.ax.plot([0], [0], [0], "o") - - self.ax.set_xlim(-1, 1) - self.ax.set_ylim(-1, 1) - self.ax.set_zlim(-1, 1) - - self.ax.plot([ref_ee_pose[0]], [ref_ee_pose[1]], [ref_ee_pose[2]], - "o") - plt.show() - - def euler_angle(self): - trans = self.transformation_matrix() - - alpha = math.atan2(trans[1][2], trans[0][2]) - if not (-math.pi / 2 <= alpha <= math.pi / 2): - alpha = math.atan2(trans[1][2], trans[0][2]) + math.pi - if not (-math.pi / 2 <= alpha <= math.pi / 2): - alpha = math.atan2(trans[1][2], trans[0][2]) - math.pi - beta = math.atan2( - trans[0][2] * math.cos(alpha) + trans[1][2] * math.sin(alpha), - trans[2][2]) - gamma = math.atan2( - -trans[0][0] * math.sin(alpha) + trans[1][0] * math.cos(alpha), - -trans[0][1] * math.sin(alpha) + trans[1][1] * math.cos(alpha)) - - return alpha, beta, gamma - - def set_joint_angles(self, joint_angle_list): - for i in range(len(self.link_list)): - self.link_list[i].dh_params_[0] = joint_angle_list[i] - - def update_joint_angles(self, diff_joint_angle_list): - for i in range(len(self.link_list)): - self.link_list[i].dh_params_[0] += diff_joint_angle_list[i] - - def plot(self): - self.fig = plt.figure() - self.ax = Axes3D(self.fig) - - x_list = [] - y_list = [] - z_list = [] - - trans = np.identity(4) - - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - for i in range(len(self.link_list)): - trans = np.dot(trans, self.link_list[i].transformation_matrix()) - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - - self.ax.plot(x_list, y_list, z_list, "o-", color="#00aa00", ms=4, - mew=0.5) - self.ax.plot([0], [0], [0], "o") - - self.ax.set_xlabel("x") - self.ax.set_ylabel("y") - self.ax.set_zlabel("z") - - self.ax.set_xlim(-1, 1) - self.ax.set_ylim(-1, 1) - self.ax.set_zlim(-1, 1) - plt.show() diff --git a/ArmNavigation/n_joint_arm_3d/__init__.py b/ArmNavigation/n_joint_arm_3d/__init__.py deleted file mode 100644 index 2194d4c3033..00000000000 --- a/ArmNavigation/n_joint_arm_3d/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent)) diff --git a/ArmNavigation/n_joint_arm_3d/random_forward_kinematics.py b/ArmNavigation/n_joint_arm_3d/random_forward_kinematics.py deleted file mode 100644 index f9caace3006..00000000000 --- a/ArmNavigation/n_joint_arm_3d/random_forward_kinematics.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Forward Kinematics for an n-link arm in 3D -Author: Takayuki Murooka (takayuki5168) -""" -import math -from NLinkArm3d import NLinkArm -import random - - -def random_val(min_val, max_val): - return min_val + random.random() * (max_val - min_val) - - -def main(): - print("Start solving Forward Kinematics 10 times") - # init NLinkArm with Denavit-Hartenberg parameters of PR2 - n_link_arm = NLinkArm([[0., -math.pi / 2, .1, 0.], - [math.pi / 2, math.pi / 2, 0., 0.], - [0., -math.pi / 2, 0., .4], - [0., math.pi / 2, 0., 0.], - [0., -math.pi / 2, 0., .321], - [0., math.pi / 2, 0., 0.], - [0., 0., 0., 0.]]) - # execute FK 10 times - for _ in range(10): - n_link_arm.set_joint_angles( - [random_val(-1, 1) for _ in range(len(n_link_arm.link_list))]) - - n_link_arm.forward_kinematics(plot=True) - - -if __name__ == "__main__": - main() diff --git a/ArmNavigation/n_joint_arm_3d/random_inverse_kinematics.py b/ArmNavigation/n_joint_arm_3d/random_inverse_kinematics.py deleted file mode 100644 index 91f6f1bba0f..00000000000 --- a/ArmNavigation/n_joint_arm_3d/random_inverse_kinematics.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Inverse Kinematics for an n-link arm in 3D -Author: Takayuki Murooka (takayuki5168) -""" -import math -from NLinkArm3d import NLinkArm -import random - - -def random_val(min_val, max_val): - return min_val + random.random() * (max_val - min_val) - - -def main(): - print("Start solving Inverse Kinematics 10 times") - # init NLinkArm with Denavit-Hartenberg parameters of PR2 - n_link_arm = NLinkArm([[0., -math.pi / 2, .1, 0.], - [math.pi / 2, math.pi / 2, 0., 0.], - [0., -math.pi / 2, 0., .4], - [0., math.pi / 2, 0., 0.], - [0., -math.pi / 2, 0., .321], - [0., math.pi / 2, 0., 0.], - [0., 0., 0., 0.]]) - # execute IK 10 times - for _ in range(10): - n_link_arm.inverse_kinematics([random_val(-0.5, 0.5), - random_val(-0.5, 0.5), - random_val(-0.5, 0.5), - random_val(-0.5, 0.5), - random_val(-0.5, 0.5), - random_val(-0.5, 0.5)], plot=True) - - -if __name__ == "__main__": - main() diff --git a/ArmNavigation/n_joint_arm_to_point_control/NLinkArm.py b/ArmNavigation/n_joint_arm_to_point_control/NLinkArm.py deleted file mode 100644 index 854ade90383..00000000000 --- a/ArmNavigation/n_joint_arm_to_point_control/NLinkArm.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Class for controlling and plotting an arm with an arbitrary number of links. - -Author: Daniel Ingram -""" - -import numpy as np -import matplotlib.pyplot as plt - - -class NLinkArm(object): - def __init__(self, link_lengths, joint_angles, goal, show_animation): - self.show_animation = show_animation - self.n_links = len(link_lengths) - if self.n_links != len(joint_angles): - raise ValueError() - - self.link_lengths = np.array(link_lengths) - self.joint_angles = np.array(joint_angles) - self.points = [[0, 0] for _ in range(self.n_links + 1)] - - self.lim = sum(link_lengths) - self.goal = np.array(goal).T - - if show_animation: # pragma: no cover - self.fig = plt.figure() - self.fig.canvas.mpl_connect('button_press_event', self.click) - - plt.ion() - plt.show() - - self.update_points() - - def update_joints(self, joint_angles): - self.joint_angles = joint_angles - - self.update_points() - - def update_points(self): - for i in range(1, self.n_links + 1): - self.points[i][0] = self.points[i - 1][0] + \ - self.link_lengths[i - 1] * \ - np.cos(np.sum(self.joint_angles[:i])) - self.points[i][1] = self.points[i - 1][1] + \ - self.link_lengths[i - 1] * \ - np.sin(np.sum(self.joint_angles[:i])) - - self.end_effector = np.array(self.points[self.n_links]).T - if self.show_animation: # pragma: no cover - self.plot() - - def plot(self): # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - for i in range(self.n_links + 1): - if i is not self.n_links: - plt.plot([self.points[i][0], self.points[i + 1][0]], - [self.points[i][1], self.points[i + 1][1]], 'r-') - plt.plot(self.points[i][0], self.points[i][1], 'ko') - - plt.plot(self.goal[0], self.goal[1], 'gx') - - plt.plot([self.end_effector[0], self.goal[0]], [ - self.end_effector[1], self.goal[1]], 'g--') - - plt.xlim([-self.lim, self.lim]) - plt.ylim([-self.lim, self.lim]) - plt.draw() - plt.pause(0.0001) - - def click(self, event): - self.goal = np.array([event.xdata, event.ydata]).T - self.plot() diff --git a/ArmNavigation/n_joint_arm_to_point_control/__init__.py b/ArmNavigation/n_joint_arm_to_point_control/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/ArmNavigation/n_joint_arm_to_point_control/n_joint_arm_to_point_control.py b/ArmNavigation/n_joint_arm_to_point_control/n_joint_arm_to_point_control.py deleted file mode 100644 index a2375233367..00000000000 --- a/ArmNavigation/n_joint_arm_to_point_control/n_joint_arm_to_point_control.py +++ /dev/null @@ -1,168 +0,0 @@ -""" -Inverse kinematics for an n-link arm using the Jacobian inverse method - -Author: Daniel Ingram (daniel-s-ingram) - Atsushi Sakai (@Atsushi_twi) -""" - -import sys -from pathlib import Path -sys.path.append(str(Path(__file__).parent.parent.parent)) - -import numpy as np -from ArmNavigation.n_joint_arm_to_point_control.NLinkArm import NLinkArm -from utils.angle import angle_mod - -# Simulation parameters -Kp = 2 -dt = 0.1 -N_LINKS = 10 -N_ITERATIONS = 10000 - -# States -WAIT_FOR_NEW_GOAL = 1 -MOVING_TO_GOAL = 2 - -show_animation = True - - -def main(): # pragma: no cover - """ - Creates an arm using the NLinkArm class and uses its inverse kinematics - to move it to the desired position. - """ - link_lengths = [1] * N_LINKS - joint_angles = np.array([0] * N_LINKS) - goal_pos = [N_LINKS, 0] - arm = NLinkArm(link_lengths, joint_angles, goal_pos, show_animation) - state = WAIT_FOR_NEW_GOAL - solution_found = False - while True: - old_goal = np.array(goal_pos) - goal_pos = np.array(arm.goal) - end_effector = arm.end_effector - errors, distance = distance_to_goal(end_effector, goal_pos) - - # State machine to allow changing of goal before current goal has been reached - if state is WAIT_FOR_NEW_GOAL: - if distance > 0.1 and not solution_found: - joint_goal_angles, solution_found = inverse_kinematics( - link_lengths, joint_angles, goal_pos) - if not solution_found: - print("Solution could not be found.") - state = WAIT_FOR_NEW_GOAL - arm.goal = end_effector - elif solution_found: - state = MOVING_TO_GOAL - elif state is MOVING_TO_GOAL: - if distance > 0.1 and all(old_goal == goal_pos): - joint_angles = joint_angles + Kp * \ - ang_diff(joint_goal_angles, joint_angles) * dt - else: - state = WAIT_FOR_NEW_GOAL - solution_found = False - - arm.update_joints(joint_angles) - - -def inverse_kinematics(link_lengths, joint_angles, goal_pos): - """ - Calculates the inverse kinematics using the Jacobian inverse method. - """ - for iteration in range(N_ITERATIONS): - current_pos = forward_kinematics(link_lengths, joint_angles) - errors, distance = distance_to_goal(current_pos, goal_pos) - if distance < 0.1: - print("Solution found in %d iterations." % iteration) - return joint_angles, True - J = jacobian_inverse(link_lengths, joint_angles) - joint_angles = joint_angles + np.matmul(J, errors) - return joint_angles, False - - -def get_random_goal(): - from random import random - SAREA = 15.0 - return [SAREA * random() - SAREA / 2.0, - SAREA * random() - SAREA / 2.0] - - -def animation(): - link_lengths = [1] * N_LINKS - joint_angles = np.array([0] * N_LINKS) - goal_pos = get_random_goal() - arm = NLinkArm(link_lengths, joint_angles, goal_pos, show_animation) - state = WAIT_FOR_NEW_GOAL - solution_found = False - - i_goal = 0 - while True: - old_goal = np.array(goal_pos) - goal_pos = np.array(arm.goal) - end_effector = arm.end_effector - errors, distance = distance_to_goal(end_effector, goal_pos) - - # State machine to allow changing of goal before current goal has been reached - if state is WAIT_FOR_NEW_GOAL: - - if distance > 0.1 and not solution_found: - joint_goal_angles, solution_found = inverse_kinematics( - link_lengths, joint_angles, goal_pos) - if not solution_found: - print("Solution could not be found.") - state = WAIT_FOR_NEW_GOAL - arm.goal = get_random_goal() - elif solution_found: - state = MOVING_TO_GOAL - elif state is MOVING_TO_GOAL: - if distance > 0.1 and all(old_goal == goal_pos): - joint_angles = joint_angles + Kp * \ - ang_diff(joint_goal_angles, joint_angles) * dt - else: - state = WAIT_FOR_NEW_GOAL - solution_found = False - arm.goal = get_random_goal() - i_goal += 1 - - if i_goal >= 5: - break - - arm.update_joints(joint_angles) - - -def forward_kinematics(link_lengths, joint_angles): - x = y = 0 - for i in range(1, N_LINKS + 1): - x += link_lengths[i - 1] * np.cos(np.sum(joint_angles[:i])) - y += link_lengths[i - 1] * np.sin(np.sum(joint_angles[:i])) - return np.array([x, y]).T - - -def jacobian_inverse(link_lengths, joint_angles): - J = np.zeros((2, N_LINKS)) - for i in range(N_LINKS): - J[0, i] = 0 - J[1, i] = 0 - for j in range(i, N_LINKS): - J[0, i] -= link_lengths[j] * np.sin(np.sum(joint_angles[:j])) - J[1, i] += link_lengths[j] * np.cos(np.sum(joint_angles[:j])) - - return np.linalg.pinv(J) - - -def distance_to_goal(current_pos, goal_pos): - x_diff = goal_pos[0] - current_pos[0] - y_diff = goal_pos[1] - current_pos[1] - return np.array([x_diff, y_diff]).T, np.hypot(x_diff, y_diff) - - -def ang_diff(theta1, theta2): - """ - Returns the difference between two angles in the range -pi to +pi - """ - return angle_mod(theta1 - theta2) - - -if __name__ == '__main__': - # main() - animation() diff --git a/ArmNavigation/rrt_star_seven_joint_arm_control/rrt_star_seven_joint_arm_control.py b/ArmNavigation/rrt_star_seven_joint_arm_control/rrt_star_seven_joint_arm_control.py deleted file mode 100755 index 3bc2a5ec1d7..00000000000 --- a/ArmNavigation/rrt_star_seven_joint_arm_control/rrt_star_seven_joint_arm_control.py +++ /dev/null @@ -1,405 +0,0 @@ -""" -RRT* path planner for a seven joint arm -Author: Mahyar Abdeetedal (mahyaret) -""" -import math -import random -import numpy as np -import matplotlib.pyplot as plt -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from n_joint_arm_3d.NLinkArm3d import NLinkArm - -show_animation = True -verbose = False - - -class RobotArm(NLinkArm): - def get_points(self, joint_angle_list): - self.set_joint_angles(joint_angle_list) - - x_list = [] - y_list = [] - z_list = [] - - trans = np.identity(4) - - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - for i in range(len(self.link_list)): - trans = np.dot(trans, self.link_list[i].transformation_matrix()) - x_list.append(trans[0, 3]) - y_list.append(trans[1, 3]) - z_list.append(trans[2, 3]) - - return x_list, y_list, z_list - - -class RRTStar: - """ - Class for RRT Star planning - """ - - class Node: - def __init__(self, x): - self.x = x - self.parent = None - self.cost = 0.0 - - def __init__(self, start, goal, robot, obstacle_list, rand_area, - expand_dis=.30, - path_resolution=.1, - goal_sample_rate=20, - max_iter=300, - connect_circle_dist=50.0 - ): - """ - Setting Parameter - - start:Start Position [q1,...,qn] - goal:Goal Position [q1,...,qn] - obstacleList:obstacle Positions [[x,y,z,size],...] - randArea:Random Sampling Area [min,max] - - """ - self.start = self.Node(start) - self.end = self.Node(goal) - self.dimension = len(start) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.expand_dis = expand_dis - self.path_resolution = path_resolution - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.robot = robot - self.obstacle_list = obstacle_list - self.connect_circle_dist = connect_circle_dist - self.goal_node = self.Node(goal) - self.node_list = [] - if show_animation: - self.ax = plt.axes(projection='3d') - - def planning(self, animation=False, search_until_max_iter=False): - """ - rrt star path planning - - animation: flag for animation on or off - search_until_max_iter: search until max iteration for path - improving or not - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - if verbose: - print("Iter:", i, ", number of nodes:", len(self.node_list)) - rnd = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd) - new_node = self.steer(self.node_list[nearest_ind], - rnd, - self.expand_dis) - - if self.check_collision(new_node, self.robot, self.obstacle_list): - near_inds = self.find_near_nodes(new_node) - new_node = self.choose_parent(new_node, near_inds) - if new_node: - self.node_list.append(new_node) - self.rewire(new_node, near_inds) - - if animation and i % 5 == 0 and self.dimension <= 3: - self.draw_graph(rnd) - - if (not search_until_max_iter) and new_node: - last_index = self.search_best_goal_node() - if last_index is not None: - return self.generate_final_course(last_index) - if verbose: - print("reached max iteration") - - last_index = self.search_best_goal_node() - if last_index is not None: - return self.generate_final_course(last_index) - - return None - - def choose_parent(self, new_node, near_inds): - if not near_inds: - return None - - # search nearest cost in near_inds - costs = [] - for i in near_inds: - near_node = self.node_list[i] - t_node = self.steer(near_node, new_node) - if t_node and self.check_collision(t_node, - self.robot, - self.obstacle_list): - costs.append(self.calc_new_cost(near_node, new_node)) - else: - costs.append(float("inf")) # the cost of collision node - min_cost = min(costs) - - if min_cost == float("inf"): - print("There is no good path.(min_cost is inf)") - return None - - min_ind = near_inds[costs.index(min_cost)] - new_node = self.steer(self.node_list[min_ind], new_node) - new_node.parent = self.node_list[min_ind] - new_node.cost = min_cost - - return new_node - - def search_best_goal_node(self): - dist_to_goal_list = [self.calc_dist_to_goal(n.x) - for n in self.node_list] - goal_inds = [dist_to_goal_list.index(i) - for i in dist_to_goal_list if i <= self.expand_dis] - - safe_goal_inds = [] - for goal_ind in goal_inds: - t_node = self.steer(self.node_list[goal_ind], self.goal_node) - if self.check_collision(t_node, self.robot, self.obstacle_list): - safe_goal_inds.append(goal_ind) - - if not safe_goal_inds: - return None - - min_cost = min([self.node_list[i].cost for i in safe_goal_inds]) - for i in safe_goal_inds: - if self.node_list[i].cost == min_cost: - return i - - return None - - def find_near_nodes(self, new_node): - nnode = len(self.node_list) + 1 - r = self.connect_circle_dist * math.sqrt(math.log(nnode) / nnode) - # if expand_dist exists, search vertices in - # a range no more than expand_dist - if hasattr(self, 'expand_dis'): - r = min(r, self.expand_dis) - dist_list = [np.sum((np.array(node.x) - np.array(new_node.x)) ** 2) - for node in self.node_list] - near_inds = [dist_list.index(i) for i in dist_list if i <= r ** 2] - return near_inds - - def rewire(self, new_node, near_inds): - for i in near_inds: - near_node = self.node_list[i] - edge_node = self.steer(new_node, near_node) - if not edge_node: - continue - edge_node.cost = self.calc_new_cost(new_node, near_node) - - no_collision = self.check_collision(edge_node, - self.robot, - self.obstacle_list) - improved_cost = near_node.cost > edge_node.cost - - if no_collision and improved_cost: - self.node_list[i] = edge_node - self.propagate_cost_to_leaves(new_node) - - def calc_new_cost(self, from_node, to_node): - d, _, _ = self.calc_distance_and_angle(from_node, to_node) - return from_node.cost + d - - def propagate_cost_to_leaves(self, parent_node): - - for node in self.node_list: - if node.parent == parent_node: - node.cost = self.calc_new_cost(parent_node, node) - self.propagate_cost_to_leaves(node) - - def generate_final_course(self, goal_ind): - path = [self.end.x] - node = self.node_list[goal_ind] - while node.parent is not None: - path.append(node.x) - node = node.parent - path.append(node.x) - reversed(path) - return path - - def calc_dist_to_goal(self, x): - distance = np.linalg.norm(np.array(x) - np.array(self.end.x)) - return distance - - def get_random_node(self): - if random.randint(0, 100) > self.goal_sample_rate: - rnd = self.Node(np.random.uniform(self.min_rand, - self.max_rand, - self.dimension)) - else: # goal point sampling - rnd = self.Node(self.end.x) - return rnd - - def steer(self, from_node, to_node, extend_length=float("inf")): - new_node = self.Node(list(from_node.x)) - d, phi, theta = self.calc_distance_and_angle(new_node, to_node) - - new_node.path_x = [list(new_node.x)] - - if extend_length > d: - extend_length = d - - n_expand = math.floor(extend_length / self.path_resolution) - - start, end = np.array(from_node.x), np.array(to_node.x) - v = end - start - u = v / (np.sqrt(np.sum(v ** 2))) - for _ in range(n_expand): - new_node.x += u * self.path_resolution - new_node.path_x.append(list(new_node.x)) - - d, _, _ = self.calc_distance_and_angle(new_node, to_node) - if d <= self.path_resolution: - new_node.path_x.append(list(to_node.x)) - - new_node.parent = from_node - - return new_node - - def draw_graph(self, rnd=None): - plt.cla() - self.ax.axis([-1, 1, -1, 1, -1, 1]) - self.ax.set_zlim(0, 1) - self.ax.grid(True) - for (ox, oy, oz, size) in self.obstacle_list: - self.plot_sphere(self.ax, ox, oy, oz, size=size) - if self.dimension > 3: - return self.ax - if rnd is not None: - self.ax.plot([rnd.x[0]], [rnd.x[1]], [rnd.x[2]], "^k") - for node in self.node_list: - if node.parent: - path = np.array(node.path_x) - plt.plot(path[:, 0], path[:, 1], path[:, 2], "-g") - self.ax.plot([self.start.x[0]], [self.start.x[1]], - [self.start.x[2]], "xr") - self.ax.plot([self.end.x[0]], [self.end.x[1]], [self.end.x[2]], "xr") - plt.pause(0.01) - return self.ax - - @staticmethod - def get_nearest_node_index(node_list, rnd_node): - dlist = [np.sum((np.array(node.x) - np.array(rnd_node.x))**2) - for node in node_list] - minind = dlist.index(min(dlist)) - - return minind - - @staticmethod - def plot_sphere(ax, x, y, z, size=1, color="k"): - u, v = np.mgrid[0:2*np.pi:20j, 0:np.pi:10j] - xl = x+size*np.cos(u)*np.sin(v) - yl = y+size*np.sin(u)*np.sin(v) - zl = z+size*np.cos(v) - ax.plot_wireframe(xl, yl, zl, color=color) - - @staticmethod - def calc_distance_and_angle(from_node, to_node): - dx = to_node.x[0] - from_node.x[0] - dy = to_node.x[1] - from_node.x[1] - dz = to_node.x[2] - from_node.x[2] - d = np.sqrt(np.sum((np.array(to_node.x) - np.array(from_node.x))**2)) - phi = math.atan2(dy, dx) - theta = math.atan2(math.hypot(dx, dy), dz) - return d, phi, theta - - @staticmethod - def calc_distance_and_angle2(from_node, to_node): - dx = to_node.x[0] - from_node.x[0] - dy = to_node.x[1] - from_node.x[1] - dz = to_node.x[2] - from_node.x[2] - d = math.sqrt(dx**2 + dy**2 + dz**2) - phi = math.atan2(dy, dx) - theta = math.atan2(math.hypot(dx, dy), dz) - return d, phi, theta - - @staticmethod - def check_collision(node, robot, obstacleList): - - if node is None: - return False - - for (ox, oy, oz, size) in obstacleList: - for x in node.path_x: - x_list, y_list, z_list = robot.get_points(x) - dx_list = [ox - x_point for x_point in x_list] - dy_list = [oy - y_point for y_point in y_list] - dz_list = [oz - z_point for z_point in z_list] - d_list = [dx * dx + dy * dy + dz * dz - for (dx, dy, dz) in zip(dx_list, - dy_list, - dz_list)] - - if min(d_list) <= size ** 2: - return False # collision - - return True # safe - - -def main(): - print("Start " + __file__) - - # init NLinkArm with Denavit-Hartenberg parameters of panda - # https://frankaemika.github.io/docs/control_parameters.html - # [theta, alpha, a, d] - seven_joint_arm = RobotArm([[0., math.pi/2., 0., .333], - [0., -math.pi/2., 0., 0.], - [0., math.pi/2., 0.0825, 0.3160], - [0., -math.pi/2., -0.0825, 0.], - [0., math.pi/2., 0., 0.3840], - [0., math.pi/2., 0.088, 0.], - [0., 0., 0., 0.107]]) - # ====Search Path with RRT==== - obstacle_list = [ - (-.3, -.3, .7, .1), - (.0, -.3, .7, .1), - (.2, -.1, .3, .15), - ] # [x,y,size(radius)] - start = [0 for _ in range(len(seven_joint_arm.link_list))] - end = [1.5 for _ in range(len(seven_joint_arm.link_list))] - # Set Initial parameters - rrt_star = RRTStar(start=start, - goal=end, - rand_area=[0, 2], - max_iter=200, - robot=seven_joint_arm, - obstacle_list=obstacle_list) - path = rrt_star.planning(animation=show_animation, - search_until_max_iter=False) - - if path is None: - print("Cannot find path.") - else: - print("Found path!") - - # Draw final path - if show_animation: - ax = rrt_star.draw_graph() - - # Plot final configuration - x_points, y_points, z_points = seven_joint_arm.get_points(path[-1]) - ax.plot([x for x in x_points], - [y for y in y_points], - [z for z in z_points], - "o-", color="red", ms=5, mew=0.5) - - for i, q in enumerate(path): - x_points, y_points, z_points = seven_joint_arm.get_points(q) - ax.plot([x for x in x_points], - [y for y in y_points], - [z for z in z_points], - "o-", color="grey", ms=4, mew=0.5) - plt.pause(0.1) - - plt.show() - - -if __name__ == '__main__': - main() diff --git a/ArmNavigation/two_joint_arm_to_point_control/two_joint_arm_to_point_control.py b/ArmNavigation/two_joint_arm_to_point_control/two_joint_arm_to_point_control.py deleted file mode 100644 index c2227f18e35..00000000000 --- a/ArmNavigation/two_joint_arm_to_point_control/two_joint_arm_to_point_control.py +++ /dev/null @@ -1,145 +0,0 @@ -""" -Inverse kinematics of a two-joint arm -Left-click the plot to set the goal position of the end effector - -Author: Daniel Ingram (daniel-s-ingram) - Atsushi Sakai (@Atsushi_twi) - -Ref: P. I. Corke, "Robotics, Vision & Control", Springer 2017, - ISBN 978-3-319-54413-7 p102 -- [Robotics, Vision and Control] -(https://link.springer.com/book/10.1007/978-3-642-20144-8) - -""" - -import matplotlib.pyplot as plt -import numpy as np -import math -from utils.angle import angle_mod - - -# Simulation parameters -Kp = 15 -dt = 0.01 - -# Link lengths -l1 = l2 = 1 - -# Set initial goal position to the initial end-effector position -x = 2 -y = 0 - -show_animation = True - -if show_animation: - plt.ion() - - -def two_joint_arm(GOAL_TH=0.0, theta1=0.0, theta2=0.0): - """ - Computes the inverse kinematics for a planar 2DOF arm - When out of bounds, rewrite x and y with last correct values - """ - global x, y - x_prev, y_prev = None, None - while True: - try: - if x is not None and y is not None: - x_prev = x - y_prev = y - if np.hypot(x, y) > (l1 + l2): - theta2_goal = 0 - else: - theta2_goal = np.arccos( - (x**2 + y**2 - l1**2 - l2**2) / (2 * l1 * l2)) - tmp = math.atan2(l2 * np.sin(theta2_goal), - (l1 + l2 * np.cos(theta2_goal))) - theta1_goal = math.atan2(y, x) - tmp - - if theta1_goal < 0: - theta2_goal = -theta2_goal - tmp = math.atan2(l2 * np.sin(theta2_goal), - (l1 + l2 * np.cos(theta2_goal))) - theta1_goal = math.atan2(y, x) - tmp - - theta1 = theta1 + Kp * ang_diff(theta1_goal, theta1) * dt - theta2 = theta2 + Kp * ang_diff(theta2_goal, theta2) * dt - except ValueError as e: - print("Unreachable goal"+e) - except TypeError: - x = x_prev - y = y_prev - - wrist = plot_arm(theta1, theta2, x, y) - - # check goal - d2goal = None - if x is not None and y is not None: - d2goal = np.hypot(wrist[0] - x, wrist[1] - y) - - if abs(d2goal) < GOAL_TH and x is not None: - return theta1, theta2 - - -def plot_arm(theta1, theta2, target_x, target_y): # pragma: no cover - shoulder = np.array([0, 0]) - elbow = shoulder + np.array([l1 * np.cos(theta1), l1 * np.sin(theta1)]) - wrist = elbow + \ - np.array([l2 * np.cos(theta1 + theta2), l2 * np.sin(theta1 + theta2)]) - - if show_animation: - plt.cla() - - plt.plot([shoulder[0], elbow[0]], [shoulder[1], elbow[1]], 'k-') - plt.plot([elbow[0], wrist[0]], [elbow[1], wrist[1]], 'k-') - - plt.plot(shoulder[0], shoulder[1], 'ro') - plt.plot(elbow[0], elbow[1], 'ro') - plt.plot(wrist[0], wrist[1], 'ro') - - plt.plot([wrist[0], target_x], [wrist[1], target_y], 'g--') - plt.plot(target_x, target_y, 'g*') - - plt.xlim(-2, 2) - plt.ylim(-2, 2) - - plt.show() - plt.pause(dt) - - return wrist - - -def ang_diff(theta1, theta2): - # Returns the difference between two angles in the range -pi to +pi - return angle_mod(theta1 - theta2) - - -def click(event): # pragma: no cover - global x, y - x = event.xdata - y = event.ydata - - -def animation(): - from random import random - global x, y - theta1 = theta2 = 0.0 - for i in range(5): - x = 2.0 * random() - 1.0 - y = 2.0 * random() - 1.0 - theta1, theta2 = two_joint_arm( - GOAL_TH=0.01, theta1=theta1, theta2=theta2) - - -def main(): # pragma: no cover - fig = plt.figure() - fig.canvas.mpl_connect("button_press_event", click) - # for stopping simulation with the esc key. - fig.canvas.mpl_connect('key_release_event', lambda event: [ - exit(0) if event.key == 'escape' else None]) - two_joint_arm() - - -if __name__ == "__main__": - # animation() - main() diff --git a/Bipedal/__init__.py b/Bipedal/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Bipedal/bipedal_planner/__init__.py b/Bipedal/bipedal_planner/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Bipedal/bipedal_planner/bipedal_planner.py b/Bipedal/bipedal_planner/bipedal_planner.py deleted file mode 100644 index c34357df678..00000000000 --- a/Bipedal/bipedal_planner/bipedal_planner.py +++ /dev/null @@ -1,205 +0,0 @@ -""" -Bipedal Walking with modifying designated footsteps -author: Takayuki Murooka (takayuki5168) -""" -import numpy as np -import math -from matplotlib import pyplot as plt -import matplotlib.patches as pat -from mpl_toolkits.mplot3d import Axes3D -import mpl_toolkits.mplot3d.art3d as art3d - - -class BipedalPlanner(object): - def __init__(self): - self.act_p = [] # actual footstep positions - self.ref_p = [] # reference footstep positions - self.com_trajectory = [] - self.ref_footsteps = None - self.g = 9.8 - - def set_ref_footsteps(self, ref_footsteps): - self.ref_footsteps = ref_footsteps - - def inverted_pendulum(self, x, x_dot, px_star, y, y_dot, py_star, z_c, - time_width): - time_split = 100 - - for i in range(time_split): - delta_time = time_width / time_split - - x_dot2 = self.g / z_c * (x - px_star) - x += x_dot * delta_time - x_dot += x_dot2 * delta_time - - y_dot2 = self.g / z_c * (y - py_star) - y += y_dot * delta_time - y_dot += y_dot2 * delta_time - - if i % 10 == 0: - self.com_trajectory.append([x, y]) - - return x, x_dot, y, y_dot - - def walk(self, t_sup=0.8, z_c=0.8, a=10, b=1, plot=False): - if self.ref_footsteps is None: - print("No footsteps") - return - - # set up plotter - if plot: - fig = plt.figure() - ax = Axes3D(fig) - fig.add_axes(ax) - com_trajectory_for_plot = [] - - px, py = 0.0, 0.0 # reference footstep position - px_star, py_star = px, py # modified footstep position - xi, xi_dot, yi, yi_dot = 0.0, 0.0, 0.01, 0.0 - time = 0.0 - n = 0 - self.ref_p.append([px, py, 0]) - self.act_p.append([px, py, 0]) - for i in range(len(self.ref_footsteps)): - # simulate x, y and those of dot of inverted pendulum - xi, xi_dot, yi, yi_dot = self.inverted_pendulum( - xi, xi_dot, px_star, yi, yi_dot, py_star, z_c, t_sup) - - # update time - time += t_sup - n += 1 - - # calculate px, py, x_, y_, vx_, vy_ - f_x, f_y, f_theta = self.ref_footsteps[n - 1] - rotate_mat = np.array([[math.cos(f_theta), -math.sin(f_theta)], - [math.sin(f_theta), math.cos(f_theta)]]) - - if n == len(self.ref_footsteps): - f_x_next, f_y_next, f_theta_next = 0., 0., 0. - else: - f_x_next, f_y_next, f_theta_next = self.ref_footsteps[n] - rotate_mat_next = np.array( - [[math.cos(f_theta_next), -math.sin(f_theta_next)], - [math.sin(f_theta_next), math.cos(f_theta_next)]]) - - Tc = math.sqrt(z_c / self.g) - C = math.cosh(t_sup / Tc) - S = math.sinh(t_sup / Tc) - - px, py = list(np.array([px, py]) - + np.dot(rotate_mat, - np.array([f_x, -1 * math.pow(-1, n) * f_y]) - )) - x_, y_ = list(np.dot(rotate_mat_next, np.array( - [f_x_next / 2., math.pow(-1, n) * f_y_next / 2.]))) - vx_, vy_ = list(np.dot(rotate_mat_next, np.array( - [(1 + C) / (Tc * S) * x_, (C - 1) / (Tc * S) * y_]))) - self.ref_p.append([px, py, f_theta]) - - # calculate reference COM - xd, xd_dot = px + x_, vx_ - yd, yd_dot = py + y_, vy_ - - # calculate modified footsteps - D = a * math.pow(C - 1, 2) + b * math.pow(S / Tc, 2) - px_star = -a * (C - 1) / D * (xd - C * xi - Tc * S * xi_dot) \ - - b * S / (Tc * D) * (xd_dot - S / Tc * xi - C * xi_dot) - py_star = -a * (C - 1) / D * (yd - C * yi - Tc * S * yi_dot) \ - - b * S / (Tc * D) * (yd_dot - S / Tc * yi - C * yi_dot) - self.act_p.append([px_star, py_star, f_theta]) - - # plot - if plot: - self.plot_animation(ax, com_trajectory_for_plot, px_star, - py_star, z_c) - if plot: - plt.show() - - def plot_animation(self, ax, com_trajectory_for_plot, px_star, py_star, - z_c): # pragma: no cover - # for plot trajectory, plot in for loop - for c in range(len(self.com_trajectory)): - if c > len(com_trajectory_for_plot): - # set up plotter - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: - [exit(0) if event.key == 'escape' else None]) - ax.set_zlim(0, z_c * 2) - ax.set_xlim(0, 1) - ax.set_ylim(-0.5, 0.5) - - # update com_trajectory_for_plot - com_trajectory_for_plot.append(self.com_trajectory[c]) - - # plot com - ax.plot([p[0] for p in com_trajectory_for_plot], - [p[1] for p in com_trajectory_for_plot], [ - 0 for _ in com_trajectory_for_plot], - color="red") - - # plot inverted pendulum - ax.plot([px_star, com_trajectory_for_plot[-1][0]], - [py_star, com_trajectory_for_plot[-1][1]], - [0, z_c], color="green", linewidth=3) - ax.scatter([com_trajectory_for_plot[-1][0]], - [com_trajectory_for_plot[-1][1]], - [z_c], color="green", s=300) - - # foot rectangle for self.ref_p - foot_width = 0.06 - foot_height = 0.04 - for j in range(len(self.ref_p)): - angle = self.ref_p[j][2] + \ - math.atan2(foot_height, - foot_width) - math.pi - r = math.sqrt( - math.pow(foot_width / 3., 2) + math.pow( - foot_height / 2., 2)) - rec = pat.Rectangle(xy=( - self.ref_p[j][0] + r * math.cos(angle), - self.ref_p[j][1] + r * math.sin(angle)), - width=foot_width, - height=foot_height, - angle=self.ref_p[j][ - 2] * 180 / math.pi, - color="blue", fill=False, - ls=":") - ax.add_patch(rec) - art3d.pathpatch_2d_to_3d(rec, z=0, zdir="z") - - # foot rectangle for self.act_p - for j in range(len(self.act_p)): - angle = self.act_p[j][2] + \ - math.atan2(foot_height, - foot_width) - math.pi - r = math.sqrt( - math.pow(foot_width / 3., 2) + math.pow( - foot_height / 2., 2)) - rec = pat.Rectangle(xy=( - self.act_p[j][0] + r * math.cos(angle), - self.act_p[j][1] + r * math.sin(angle)), - width=foot_width, - height=foot_height, - angle=self.act_p[j][ - 2] * 180 / math.pi, - color="blue", fill=False) - ax.add_patch(rec) - art3d.pathpatch_2d_to_3d(rec, z=0, zdir="z") - - plt.draw() - plt.pause(0.001) - - -if __name__ == "__main__": - bipedal_planner = BipedalPlanner() - - footsteps = [[0.0, 0.2, 0.0], - [0.3, 0.2, 0.0], - [0.3, 0.2, 0.2], - [0.3, 0.2, 0.2], - [0.0, 0.2, 0.2]] - bipedal_planner.set_ref_footsteps(footsteps) - bipedal_planner.walk(plot=True) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index e8c4702596b..00000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at asakaig@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 3bcc499e6ae..00000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contributing - -:+1::tada: First of all, thank you very much for taking the time to contribute! :tada::+1: - -Please check this document for contribution: [How to contribute — PythonRobotics documentation](https://atsushisakai.github.io/PythonRobotics/modules/0_getting_started/3_how_to_contribute.html) diff --git a/InvertedPendulum/inverted_pendulum_lqr_control.py b/InvertedPendulum/inverted_pendulum_lqr_control.py deleted file mode 100644 index c4380530b81..00000000000 --- a/InvertedPendulum/inverted_pendulum_lqr_control.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Inverted Pendulum LQR control -author: Trung Kien - letrungkien.k53.hut@gmail.com -""" - -import math -import time - -import matplotlib.pyplot as plt -import numpy as np -from numpy.linalg import inv, eig - -# Model parameters - -l_bar = 2.0 # length of bar -M = 1.0 # [kg] -m = 0.3 # [kg] -g = 9.8 # [m/s^2] - -nx = 4 # number of state -nu = 1 # number of input -Q = np.diag([0.0, 1.0, 1.0, 0.0]) # state cost matrix -R = np.diag([0.01]) # input cost matrix - -delta_t = 0.1 # time tick [s] -sim_time = 5.0 # simulation time [s] - -show_animation = True - - -def main(): - x0 = np.array([ - [0.0], - [0.0], - [0.3], - [0.0] - ]) - - x = np.copy(x0) - time = 0.0 - - while sim_time > time: - time += delta_t - - # calc control input - u = lqr_control(x) - - # simulate inverted pendulum cart - x = simulation(x, u) - - if show_animation: - plt.clf() - px = float(x[0, 0]) - theta = float(x[2, 0]) - plot_cart(px, theta) - plt.xlim([-5.0, 2.0]) - plt.pause(0.001) - - print("Finish") - print(f"x={float(x[0, 0]):.2f} [m] , theta={math.degrees(x[2, 0]):.2f} [deg]") - if show_animation: - plt.show() - - -def simulation(x, u): - A, B = get_model_matrix() - x = A @ x + B @ u - - return x - - -def solve_DARE(A, B, Q, R, maxiter=150, eps=0.01): - """ - Solve a discrete time_Algebraic Riccati equation (DARE) - """ - P = Q - - for i in range(maxiter): - Pn = A.T @ P @ A - A.T @ P @ B @ \ - inv(R + B.T @ P @ B) @ B.T @ P @ A + Q - if (abs(Pn - P)).max() < eps: - break - P = Pn - - return Pn - - -def dlqr(A, B, Q, R): - """ - Solve the discrete time lqr controller. - x[k+1] = A x[k] + B u[k] - cost = sum x[k].T*Q*x[k] + u[k].T*R*u[k] - # ref Bertsekas, p.151 - """ - - # first, try to solve the ricatti equation - P = solve_DARE(A, B, Q, R) - - # compute the LQR gain - K = inv(B.T @ P @ B + R) @ (B.T @ P @ A) - - eigVals, eigVecs = eig(A - B @ K) - return K, P, eigVals - - -def lqr_control(x): - A, B = get_model_matrix() - start = time.time() - K, _, _ = dlqr(A, B, Q, R) - u = -K @ x - elapsed_time = time.time() - start - print(f"calc time:{elapsed_time:.6f} [sec]") - return u - - -def get_numpy_array_from_matrix(x): - """ - get build-in list from matrix - """ - return np.array(x).flatten() - - -def get_model_matrix(): - A = np.array([ - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, m * g / M, 0.0], - [0.0, 0.0, 0.0, 1.0], - [0.0, 0.0, g * (M + m) / (l_bar * M), 0.0] - ]) - A = np.eye(nx) + delta_t * A - - B = np.array([ - [0.0], - [1.0 / M], - [0.0], - [1.0 / (l_bar * M)] - ]) - B = delta_t * B - - return A, B - - -def flatten(a): - return np.array(a).flatten() - - -def plot_cart(xt, theta): - cart_w = 1.0 - cart_h = 0.5 - radius = 0.1 - - cx = np.array([-cart_w / 2.0, cart_w / 2.0, cart_w / - 2.0, -cart_w / 2.0, -cart_w / 2.0]) - cy = np.array([0.0, 0.0, cart_h, cart_h, 0.0]) - cy += radius * 2.0 - - cx = cx + xt - - bx = np.array([0.0, l_bar * math.sin(-theta)]) - bx += xt - by = np.array([cart_h, l_bar * math.cos(-theta) + cart_h]) - by += radius * 2.0 - - angles = np.arange(0.0, math.pi * 2.0, math.radians(3.0)) - ox = np.array([radius * math.cos(a) for a in angles]) - oy = np.array([radius * math.sin(a) for a in angles]) - - rwx = np.copy(ox) + cart_w / 4.0 + xt - rwy = np.copy(oy) + radius - lwx = np.copy(ox) - cart_w / 4.0 + xt - lwy = np.copy(oy) + radius - - wx = np.copy(ox) + bx[-1] - wy = np.copy(oy) + by[-1] - - plt.plot(flatten(cx), flatten(cy), "-b") - plt.plot(flatten(bx), flatten(by), "-k") - plt.plot(flatten(rwx), flatten(rwy), "-k") - plt.plot(flatten(lwx), flatten(lwy), "-k") - plt.plot(flatten(wx), flatten(wy), "-k") - plt.title(f"x: {xt:.2f} , theta: {math.degrees(theta):.2f}") - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - plt.axis("equal") - - -if __name__ == '__main__': - main() diff --git a/InvertedPendulum/inverted_pendulum_mpc_control.py b/InvertedPendulum/inverted_pendulum_mpc_control.py deleted file mode 100644 index 9a5fa2ab414..00000000000 --- a/InvertedPendulum/inverted_pendulum_mpc_control.py +++ /dev/null @@ -1,187 +0,0 @@ -""" -Inverted Pendulum MPC control -author: Atsushi Sakai -""" - -import math -import time - -import cvxpy -import matplotlib.pyplot as plt -import numpy as np - -# Model parameters - -l_bar = 2.0 # length of bar -M = 1.0 # [kg] -m = 0.3 # [kg] -g = 9.8 # [m/s^2] - -nx = 4 # number of state -nu = 1 # number of input -Q = np.diag([0.0, 1.0, 1.0, 0.0]) # state cost matrix -R = np.diag([0.01]) # input cost matrix - -T = 30 # Horizon length -delta_t = 0.1 # time tick -sim_time = 5.0 # simulation time [s] - -show_animation = True - - -def main(): - x0 = np.array([ - [0.0], - [0.0], - [0.3], - [0.0] - ]) - - x = np.copy(x0) - time = 0.0 - - while sim_time > time: - time += delta_t - - # calc control input - opt_x, opt_delta_x, opt_theta, opt_delta_theta, opt_input = \ - mpc_control(x) - - # get input - u = opt_input[0] - - # simulate inverted pendulum cart - x = simulation(x, u) - - if show_animation: - plt.clf() - px = float(x[0, 0]) - theta = float(x[2, 0]) - plot_cart(px, theta) - plt.xlim([-5.0, 2.0]) - plt.pause(0.001) - - print("Finish") - print(f"x={float(x[0, 0]):.2f} [m] , theta={math.degrees(x[2, 0]):.2f} [deg]") - if show_animation: - plt.show() - - -def simulation(x, u): - A, B = get_model_matrix() - x = np.dot(A, x) + np.dot(B, u) - - return x - - -def mpc_control(x0): - x = cvxpy.Variable((nx, T + 1)) - u = cvxpy.Variable((nu, T)) - - A, B = get_model_matrix() - - cost = 0.0 - constr = [] - for t in range(T): - cost += cvxpy.quad_form(x[:, t + 1], Q) - cost += cvxpy.quad_form(u[:, t], R) - constr += [x[:, t + 1] == A @ x[:, t] + B @ u[:, t]] - - constr += [x[:, 0] == x0[:, 0]] - prob = cvxpy.Problem(cvxpy.Minimize(cost), constr) - - start = time.time() - prob.solve(verbose=False) - elapsed_time = time.time() - start - print(f"calc time:{elapsed_time:.6f} [sec]") - - if prob.status == cvxpy.OPTIMAL: - ox = get_numpy_array_from_matrix(x.value[0, :]) - dx = get_numpy_array_from_matrix(x.value[1, :]) - theta = get_numpy_array_from_matrix(x.value[2, :]) - d_theta = get_numpy_array_from_matrix(x.value[3, :]) - - ou = get_numpy_array_from_matrix(u.value[0, :]) - else: - ox, dx, theta, d_theta, ou = None, None, None, None, None - - return ox, dx, theta, d_theta, ou - - -def get_numpy_array_from_matrix(x): - """ - get build-in list from matrix - """ - return np.array(x).flatten() - - -def get_model_matrix(): - A = np.array([ - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, m * g / M, 0.0], - [0.0, 0.0, 0.0, 1.0], - [0.0, 0.0, g * (M + m) / (l_bar * M), 0.0] - ]) - A = np.eye(nx) + delta_t * A - - B = np.array([ - [0.0], - [1.0 / M], - [0.0], - [1.0 / (l_bar * M)] - ]) - B = delta_t * B - - return A, B - - -def flatten(a): - return np.array(a).flatten() - - -def plot_cart(xt, theta): - cart_w = 1.0 - cart_h = 0.5 - radius = 0.1 - - cx = np.array([-cart_w / 2.0, cart_w / 2.0, cart_w / - 2.0, -cart_w / 2.0, -cart_w / 2.0]) - cy = np.array([0.0, 0.0, cart_h, cart_h, 0.0]) - cy += radius * 2.0 - - cx = cx + xt - - bx = np.array([0.0, l_bar * math.sin(-theta)]) - bx += xt - by = np.array([cart_h, l_bar * math.cos(-theta) + cart_h]) - by += radius * 2.0 - - angles = np.arange(0.0, math.pi * 2.0, math.radians(3.0)) - ox = np.array([radius * math.cos(a) for a in angles]) - oy = np.array([radius * math.sin(a) for a in angles]) - - rwx = np.copy(ox) + cart_w / 4.0 + xt - rwy = np.copy(oy) + radius - lwx = np.copy(ox) - cart_w / 4.0 + xt - lwy = np.copy(oy) + radius - - wx = np.copy(ox) + bx[-1] - wy = np.copy(oy) + by[-1] - - plt.plot(flatten(cx), flatten(cy), "-b") - plt.plot(flatten(bx), flatten(by), "-k") - plt.plot(flatten(rwx), flatten(rwy), "-k") - plt.plot(flatten(lwx), flatten(lwy), "-k") - plt.plot(flatten(wx), flatten(wy), "-k") - plt.title(f"x: {xt:.2f} , theta: {math.degrees(theta):.2f}") - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - plt.axis("equal") - - -if __name__ == '__main__': - main() diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 1c9b928b543..00000000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 - now Atsushi Sakai and other contributors: -https://github.com/AtsushiSakai/PythonRobotics/contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Localization/__init__.py b/Localization/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Localization/cubature_kalman_filter/cubature_kalman_filter.py b/Localization/cubature_kalman_filter/cubature_kalman_filter.py deleted file mode 100644 index 0fc4c937600..00000000000 --- a/Localization/cubature_kalman_filter/cubature_kalman_filter.py +++ /dev/null @@ -1,246 +0,0 @@ -""" -Cubature Kalman filter using Constant Turn Rate and Velocity (CTRV) model -Fuse sensor data from IMU and GPS to obtain accurate position - -https://ieeexplore.ieee.org/document/4982682 - -Author: Raghuram Shankar - -state matrix: 2D x-y position, yaw, velocity and yaw rate -measurement matrix: 2D x-y position, velocity and yaw rate - -dt: Duration of time step -N: Number of time steps -show_final: Flag for showing final result -show_animation: Flag for showing each animation frame -show_ellipse: Flag for showing covariance ellipse -z_noise: Measurement noise -x_0: Prior state estimate matrix -P_0: Prior state estimate covariance matrix -q: Process noise covariance -hx: Measurement model matrix -r: Sensor noise covariance -SP: Sigma Points -W: Weights - -x_est: State estimate -P_est: State estimate covariance -x_true: Ground truth value of state -x_true_cat: Concatenate all ground truth states -x_est_cat: Concatenate all state estimates -z_cat: Concatenate all measurements - -""" - -import math -import matplotlib.pyplot as plt -import numpy as np -from scipy.linalg import sqrtm - - -dt = 0.1 -N = 100 - -show_final = 1 -show_animation = 0 -show_ellipse = 0 - - -z_noise = np.array([[0.1, 0.0, 0.0, 0.0], # x position [m] - [0.0, 0.1, 0.0, 0.0], # y position [m] - [0.0, 0.0, 0.1, 0.0], # velocity [m/s] - [0.0, 0.0, 0.0, 0.1]]) # yaw rate [rad/s] - - -x_0 = np.array([[0.0], # x position [m] - [0.0], # y position [m] - [0.0], # yaw [rad] - [1.0], # velocity [m/s] - [0.1]]) # yaw rate [rad/s] - - -p_0 = np.array([[1e-3, 0.0, 0.0, 0.0, 0.0], - [0.0, 1e-3, 0.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 0.0, 1.0]]) - - -q = np.array([[1e-11, 0.0, 0.0, 0.0, 0.0], - [0.0, 1e-11, 0.0, 0.0, 0.0], - [0.0, 0.0, np.deg2rad(1e-4), 0.0, 0.0], - [0.0, 0.0, 0.0, 1e-4, 0.0], - [0.0, 0.0, 0.0, 0.0, np.deg2rad(1e-4)]]) - - -hx = np.array([[1.0, 0.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 0.0, 1.0]]) - - -r = np.array([[0.015, 0.0, 0.0, 0.0], - [0.0, 0.010, 0.0, 0.0], - [0.0, 0.0, 0.1, 0.0], - [0.0, 0.0, 0.0, 0.01]])**2 - - -def cubature_kalman_filter(x_est, p_est, z): - x_pred, p_pred = cubature_prediction(x_est, p_est) - x_upd, p_upd = cubature_update(x_pred, p_pred, z) - return x_upd, p_upd - - -def f(x): - """ - Motion Model - References: - http://fusion.isif.org/proceedings/fusion08CD/papers/1569107835.pdf - https://github.com/balzer82/Kalman - """ - x[0] = x[0] + (x[3]/x[4]) * (np.sin(x[4] * dt + x[2]) - np.sin(x[2])) - x[1] = x[1] + (x[3]/x[4]) * (- np.cos(x[4] * dt + x[2]) + np.cos(x[2])) - x[2] = x[2] + x[4] * dt - x[3] = x[3] - x[4] = x[4] - return x - - -def h(x): - """Measurement Model""" - x = hx @ x - return x - - -def sigma(x, p): - """ - Unscented Transform with Cubature Rule - Generate 2n Sigma Points to represent the nonlinear motion - Assign Weights to each Sigma Point, Wi = 1/2n - Cubature Rule - Special Case of Unscented Transform - W0 = 0, no extra tuning parameters, no negative weights - """ - n = np.shape(x)[0] - SP = np.zeros((n, 2*n)) - W = np.zeros((1, 2*n)) - for i in range(n): - SD = sqrtm(p) - SP[:, i] = (x + (math.sqrt(n) * SD[:, i]).reshape((n, 1))).flatten() - SP[:, i+n] = (x - (math.sqrt(n) * SD[:, i]).reshape((n, 1))).flatten() - W[:, i] = 1/(2*n) - W[:, i+n] = W[:, i] - return SP, W - - -def cubature_prediction(x_pred, p_pred): - n = np.shape(x_pred)[0] - [SP, W] = sigma(x_pred, p_pred) - x_pred = np.zeros((n, 1)) - p_pred = q - for i in range(2*n): - x_pred = x_pred + (f(SP[:, i]).reshape((n, 1)) * W[0, i]) - for i in range(2*n): - p_step = (f(SP[:, i]).reshape((n, 1)) - x_pred) - p_pred = p_pred + (p_step @ p_step.T * W[0, i]) - return x_pred, p_pred - - -def cubature_update(x_pred, p_pred, z): - n = np.shape(x_pred)[0] - m = np.shape(z)[0] - [SP, W] = sigma(x_pred, p_pred) - y_k = np.zeros((m, 1)) - P_xy = np.zeros((n, m)) - s = r - for i in range(2*n): - y_k = y_k + (h(SP[:, i]).reshape((m, 1)) * W[0, i]) - for i in range(2*n): - p_step = (h(SP[:, i]).reshape((m, 1)) - y_k) - P_xy = P_xy + ((SP[:, i]).reshape((n, 1)) - - x_pred) @ p_step.T * W[0, i] - s = s + p_step @ p_step.T * W[0, i] - x_pred = x_pred + P_xy @ np.linalg.pinv(s) @ (z - y_k) - p_pred = p_pred - P_xy @ np.linalg.pinv(s) @ P_xy.T - return x_pred, p_pred - - -def generate_measurement(x_true): - gz = hx @ x_true - z = gz + z_noise @ np.random.randn(4, 1) - return z - - -def plot_animation(i, x_true_cat, x_est_cat, z): - if i == 0: - plt.plot(x_true_cat[0], x_true_cat[1], '.r') - plt.plot(x_est_cat[0], x_est_cat[1], '.b') - else: - plt.plot(x_true_cat[0:, 0], x_true_cat[0:, 1], 'r') - plt.plot(x_est_cat[0:, 0], x_est_cat[0:, 1], 'b') - plt.plot(z[0], z[1], '+g') - plt.grid(True) - plt.pause(0.001) - - -def plot_ellipse(x_est, p_est): - phi = np.linspace(0, 2 * math.pi, 100) - p_ellipse = np.array( - [[p_est[0, 0], p_est[0, 1]], [p_est[1, 0], p_est[1, 1]]]) - x0 = 3 * sqrtm(p_ellipse) - xy_1 = np.array([]) - xy_2 = np.array([]) - for i in range(100): - arr = np.array([[math.sin(phi[i])], [math.cos(phi[i])]]) - arr = x0 @ arr - xy_1 = np.hstack([xy_1, arr[0]]) - xy_2 = np.hstack([xy_2, arr[1]]) - plt.plot(xy_1 + x_est[0], xy_2 + x_est[1], 'r') - plt.pause(0.00001) - - -def plot_final(x_true_cat, x_est_cat, z_cat): - fig = plt.figure() - subplot = fig.add_subplot(111) - subplot.plot(x_true_cat[0:, 0], x_true_cat[0:, 1], - 'r', label='True Position') - subplot.plot(x_est_cat[0:, 0], x_est_cat[0:, 1], - 'b', label='Estimated Position') - subplot.plot(z_cat[0:, 0], z_cat[0:, 1], '+g', label='Noisy Measurements') - subplot.set_xlabel('x [m]') - subplot.set_ylabel('y [m]') - subplot.set_title('Cubature Kalman Filter - CTRV Model') - subplot.legend(loc='upper left', shadow=True, fontsize='large') - plt.grid(True) - plt.show() - - -def main(): - print(__file__ + " start!!") - x_est = x_0 - p_est = p_0 - x_true = x_0 - x_true_cat = np.array([x_0[0, 0], x_0[1, 0]]) - x_est_cat = np.array([x_0[0, 0], x_0[1, 0]]) - z_cat = np.array([x_0[0, 0], x_0[1, 0]]) - for i in range(N): - x_true = f(x_true) - z = generate_measurement(x_true) - if i == (N - 1) and show_final == 1: - show_final_flag = 1 - else: - show_final_flag = 0 - if show_animation == 1: - plot_animation(i, x_true_cat, x_est_cat, z) - if show_ellipse == 1: - plot_ellipse(x_est[0:2], p_est) - if show_final_flag == 1: - plot_final(x_true_cat, x_est_cat, z_cat) - x_est, p_est = cubature_kalman_filter(x_est, p_est, z) - x_true_cat = np.vstack((x_true_cat, x_true[0:2].T)) - x_est_cat = np.vstack((x_est_cat, x_est[0:2].T)) - z_cat = np.vstack((z_cat, z[0:2].T)) - print('CKF Over') - - -if __name__ == '__main__': - main() diff --git a/Localization/ensemble_kalman_filter/ensemble_kalman_filter.py b/Localization/ensemble_kalman_filter/ensemble_kalman_filter.py deleted file mode 100644 index 2bab3b49c1c..00000000000 --- a/Localization/ensemble_kalman_filter/ensemble_kalman_filter.py +++ /dev/null @@ -1,246 +0,0 @@ -""" - -Ensemble Kalman Filter(EnKF) localization sample - -author: Ryohei Sasaki(rsasaki0109) - -Ref: -Ensemble Kalman filtering -(https://rmets.onlinelibrary.wiley.com/doi/10.1256/qj.05.135) - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import math -import matplotlib.pyplot as plt -import numpy as np -from utils.angle import angle_mod - -from utils.angle import rot_mat_2d - -# Simulation parameter -Q_sim = np.diag([0.2, np.deg2rad(1.0)]) ** 2 -R_sim = np.diag([1.0, np.deg2rad(30.0)]) ** 2 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] -MAX_RANGE = 20.0 # maximum observation range - -# Ensemble Kalman filter parameter -NP = 20 # Number of Particle - -show_animation = True - - -def calc_input(): - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - u = np.array([[v, yaw_rate]]).T - return u - - -def observation(xTrue, xd, u, RFID): - xTrue = motion_model(xTrue, u) - - z = np.zeros((0, 4)) - - for i in range(len(RFID[:, 0])): - - dx = RFID[i, 0] - xTrue[0, 0] - dy = RFID[i, 1] - xTrue[1, 0] - d = math.hypot(dx, dy) - angle = pi_2_pi(math.atan2(dy, dx) - xTrue[2, 0]) - if d <= MAX_RANGE: - dn = d + np.random.randn() * Q_sim[0, 0] ** 0.5 # add noise - angle_with_noise = angle + np.random.randn() * Q_sim[1, 1] ** 0.5 - zi = np.array([dn, angle_with_noise, RFID[i, 0], RFID[i, 1]]) - z = np.vstack((z, zi)) - - # add noise to input - ud = np.array([[ - u[0, 0] + np.random.randn() * R_sim[0, 0] ** 0.5, - u[1, 0] + np.random.randn() * R_sim[1, 1] ** 0.5]]).T - - xd = motion_model(xd, ud) - return xTrue, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0, 0], - [0, 1.0, 0, 0], - [0, 0, 1.0, 0], - [0, 0, 0, 0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT], - [1.0, 0.0]]) - x = F.dot(x) + B.dot(u) - - return x - - -def observe_landmark_position(x, landmarks): - landmarks_pos = np.zeros((2 * landmarks.shape[0], 1)) - for (i, lm) in enumerate(landmarks): - index = 2 * i - q = Q_sim[0, 0] ** 0.5 - landmarks_pos[index] = x[0, 0] + lm[0] * math.cos( - x[2, 0] + lm[1]) + np.random.randn() * q / np.sqrt(2) - landmarks_pos[index + 1] = x[1, 0] + lm[0] * math.sin( - x[2, 0] + lm[1]) + np.random.randn() * q / np.sqrt(2) - return landmarks_pos - - -def calc_covariance(xEst, px): - cov = np.zeros((3, 3)) - - for i in range(px.shape[1]): - dx = (px[:, i] - xEst)[0:3] - cov += dx.dot(dx.T) - cov /= NP - - return cov - - -def enkf_localization(px, z, u): - """ - Localization with Ensemble Kalman filter - """ - pz = np.zeros((z.shape[0] * 2, NP)) # Particle store of z - for ip in range(NP): - x = np.array([px[:, ip]]).T - - # Predict with random input sampling - ud1 = u[0, 0] + np.random.randn() * R_sim[0, 0] ** 0.5 - ud2 = u[1, 0] + np.random.randn() * R_sim[1, 1] ** 0.5 - ud = np.array([[ud1, ud2]]).T - x = motion_model(x, ud) - px[:, ip] = x[:, 0] - z_pos = observe_landmark_position(x, z) - pz[:, ip] = z_pos[:, 0] - - x_ave = np.mean(px, axis=1) - x_dif = px - np.tile(x_ave, (NP, 1)).T - - z_ave = np.mean(pz, axis=1) - z_dif = pz - np.tile(z_ave, (NP, 1)).T - - U = 1 / (NP - 1) * x_dif @ z_dif.T - V = 1 / (NP - 1) * z_dif @ z_dif.T - - K = U @ np.linalg.inv(V) # Kalman Gain - - z_lm_pos = z[:, [2, 3]].reshape(-1, ) - - px_hat = px + K @ (np.tile(z_lm_pos, (NP, 1)).T - pz) - - xEst = np.average(px_hat, axis=1).reshape(4, 1) - PEst = calc_covariance(xEst, px_hat) - - return xEst, PEst, px_hat - - -def plot_covariance_ellipse(xEst, PEst): # pragma: no cover - Pxy = PEst[0:2, 0:2] - eig_val, eig_vec = np.linalg.eig(Pxy) - - if eig_val[0] >= eig_val[1]: - big_ind = 0 - small_ind = 1 - else: - big_ind = 1 - small_ind = 0 - - t = np.arange(0, 2 * math.pi + 0.1, 0.1) - - # eig_val[big_ind] or eiq_val[small_ind] were occasionally negative - # numbers extremely close to 0 (~10^-20), catch these cases and set - # the respective variable to 0 - try: - a = math.sqrt(eig_val[big_ind]) - except ValueError: - a = 0 - - try: - b = math.sqrt(eig_val[small_ind]) - except ValueError: - b = 0 - - x = [a * math.cos(it) for it in t] - y = [b * math.sin(it) for it in t] - angle = math.atan2(eig_vec[1, big_ind], eig_vec[0, big_ind]) - fx = np.stack([x, y]).T @ rot_mat_2d(angle) - - px = np.array(fx[:, 0] + xEst[0, 0]).flatten() - py = np.array(fx[:, 1] + xEst[1, 0]).flatten() - plt.plot(px, py, "--r") - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # RF_ID positions [x, y] - RF_ID = np.array([[10.0, 0.0], - [10.0, 10.0], - [0.0, 15.0], - [-5.0, 20.0]]) - - # State Vector [x y yaw v]' - xEst = np.zeros((4, 1)) - xTrue = np.zeros((4, 1)) - px = np.zeros((4, NP)) # Particle store of x - - xDR = np.zeros((4, 1)) # Dead reckoning - - # history - hxEst = xEst - hxTrue = xTrue - hxDR = xTrue - - while SIM_TIME >= time: - time += DT - u = calc_input() - - xTrue, z, xDR, ud = observation(xTrue, xDR, u, RF_ID) - - xEst, PEst, px = enkf_localization(px, z, ud) - - # store data history - hxEst = np.hstack((hxEst, xEst)) - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - for i in range(len(z[:, 0])): - plt.plot([xTrue[0, 0], z[i, 2]], [xTrue[1, 0], z[i, 3]], "-k") - plt.plot(RF_ID[:, 0], RF_ID[:, 1], "*k") - plt.plot(px[0, :], px[1, :], ".r") - plt.plot(np.array(hxTrue[0, :]).flatten(), - np.array(hxTrue[1, :]).flatten(), "-b") - plt.plot(np.array(hxDR[0, :]).flatten(), - np.array(hxDR[1, :]).flatten(), "-k") - plt.plot(np.array(hxEst[0, :]).flatten(), - np.array(hxEst[1, :]).flatten(), "-r") - plot_covariance_ellipse(xEst, PEst) - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/Localization/extended_kalman_filter/ekf_with_velocity_correction.py b/Localization/extended_kalman_filter/ekf_with_velocity_correction.py deleted file mode 100644 index 5dd97830fc4..00000000000 --- a/Localization/extended_kalman_filter/ekf_with_velocity_correction.py +++ /dev/null @@ -1,198 +0,0 @@ -""" - -Extended kalman filter (EKF) localization with velocity correction sample - -author: Atsushi Sakai (@Atsushi_twi) -modified by: Ryohei Sasaki (@rsasaki0109) - -""" -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import math -import matplotlib.pyplot as plt -import numpy as np - -from utils.plot import plot_covariance_ellipse - -# Covariance for EKF simulation -Q = np.diag([ - 0.1, # variance of location on x-axis - 0.1, # variance of location on y-axis - np.deg2rad(1.0), # variance of yaw angle - 0.4, # variance of velocity - 0.1 # variance of scale factor -]) ** 2 # predict state covariance -R = np.diag([0.1, 0.1]) ** 2 # Observation x,y position covariance - -# Simulation parameter -INPUT_NOISE = np.diag([0.1, np.deg2rad(5.0)]) ** 2 -GPS_NOISE = np.diag([0.05, 0.05]) ** 2 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] - -show_animation = True - - -def calc_input(): - v = 1.0 # [m/s] - yawrate = 0.1 # [rad/s] - u = np.array([[v], [yawrate]]) - return u - - -def observation(xTrue, xd, u): - xTrue = motion_model(xTrue, u) - - # add noise to gps x-y - z = observation_model(xTrue) + GPS_NOISE @ np.random.randn(2, 1) - - # add noise to input - ud = u + INPUT_NOISE @ np.random.randn(2, 1) - - xd = motion_model(xd, ud) - - return xTrue, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0, 0, 0], - [0, 1.0, 0, 0, 0], - [0, 0, 1.0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 1.0]]) - - B = np.array([[DT * math.cos(x[2, 0]) * x[4, 0], 0], - [DT * math.sin(x[2, 0]) * x[4, 0], 0], - [0.0, DT], - [1.0, 0.0], - [0.0, 0.0]]) - - x = F @ x + B @ u - - return x - - -def observation_model(x): - H = np.array([ - [1, 0, 0, 0, 0], - [0, 1, 0, 0, 0] - ]) - z = H @ x - - return z - - -def jacob_f(x, u): - """ - Jacobian of Motion Model - - motion model - x_{t+1} = x_t+v*s*dt*cos(yaw) - y_{t+1} = y_t+v*s*dt*sin(yaw) - yaw_{t+1} = yaw_t+omega*dt - v_{t+1} = v{t} - s_{t+1} = s{t} - so - dx/dyaw = -v*s*dt*sin(yaw) - dx/dv = dt*s*cos(yaw) - dx/ds = dt*v*cos(yaw) - dy/dyaw = v*s*dt*cos(yaw) - dy/dv = dt*s*sin(yaw) - dy/ds = dt*v*sin(yaw) - """ - yaw = x[2, 0] - v = u[0, 0] - s = x[4, 0] - jF = np.array([ - [1.0, 0.0, -DT * v * s * math.sin(yaw), DT * s * math.cos(yaw), DT * v * math.cos(yaw)], - [0.0, 1.0, DT * v * s * math.cos(yaw), DT * s * math.sin(yaw), DT * v * math.sin(yaw)], - [0.0, 0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 0.0, 1.0]]) - return jF - - -def jacob_h(): - jH = np.array([[1, 0, 0, 0, 0], - [0, 1, 0, 0, 0]]) - return jH - - -def ekf_estimation(xEst, PEst, z, u): - # Predict - xPred = motion_model(xEst, u) - jF = jacob_f(xEst, u) - PPred = jF @ PEst @ jF.T + Q - - # Update - jH = jacob_h() - zPred = observation_model(xPred) - y = z - zPred - S = jH @ PPred @ jH.T + R - K = PPred @ jH.T @ np.linalg.inv(S) - xEst = xPred + K @ y - PEst = (np.eye(len(xEst)) - K @ jH) @ PPred - return xEst, PEst - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # State Vector [x y yaw v s]' - xEst = np.zeros((5, 1)) - xEst[4, 0] = 1.0 # Initial scale factor - xTrue = np.zeros((5, 1)) - true_scale_factor = 0.9 # True scale factor - xTrue[4, 0] = true_scale_factor - PEst = np.eye(5) - - xDR = np.zeros((5, 1)) # Dead reckoning - - # history - hxEst = xEst - hxTrue = xTrue - hxDR = xTrue - hz = np.zeros((2, 1)) - - while SIM_TIME >= time: - time += DT - u = calc_input() - - xTrue, z, xDR, ud = observation(xTrue, xDR, u) - - xEst, PEst = ekf_estimation(xEst, PEst, z, ud) - - # store data history - hxEst = np.hstack((hxEst, xEst)) - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - hz = np.hstack((hz, z)) - estimated_scale_factor = hxEst[4, -1] - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(hz[0, :], hz[1, :], ".g") - plt.plot(hxTrue[0, :].flatten(), - hxTrue[1, :].flatten(), "-b") - plt.plot(hxDR[0, :].flatten(), - hxDR[1, :].flatten(), "-k") - plt.plot(hxEst[0, :].flatten(), - hxEst[1, :].flatten(), "-r") - plt.text(0.45, 0.85, f"True Velocity Scale Factor: {true_scale_factor:.2f}", ha='left', va='top', transform=plt.gca().transAxes) - plt.text(0.45, 0.95, f"Estimated Velocity Scale Factor: {estimated_scale_factor:.2f}", ha='left', va='top', transform=plt.gca().transAxes) - plot_covariance_ellipse(xEst[0, 0], xEst[1, 0], PEst) - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/Localization/extended_kalman_filter/extended_kalman_filter.py b/Localization/extended_kalman_filter/extended_kalman_filter.py deleted file mode 100644 index d9ece6c6f38..00000000000 --- a/Localization/extended_kalman_filter/extended_kalman_filter.py +++ /dev/null @@ -1,190 +0,0 @@ -""" - -Extended kalman filter (EKF) localization sample - -author: Atsushi Sakai (@Atsushi_twi) - -""" -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import math -import matplotlib.pyplot as plt -import numpy as np - -from utils.plot import plot_covariance_ellipse - -# Covariance for EKF simulation -Q = np.diag([ - 0.1, # variance of location on x-axis - 0.1, # variance of location on y-axis - np.deg2rad(1.0), # variance of yaw angle - 1.0 # variance of velocity -]) ** 2 # predict state covariance -R = np.diag([1.0, 1.0]) ** 2 # Observation x,y position covariance - -# Simulation parameter -INPUT_NOISE = np.diag([1.0, np.deg2rad(30.0)]) ** 2 -GPS_NOISE = np.diag([0.5, 0.5]) ** 2 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] - -show_animation = True - - -def calc_input(): - v = 1.0 # [m/s] - yawrate = 0.1 # [rad/s] - u = np.array([[v], [yawrate]]) - return u - - -def observation(xTrue, xd, u): - xTrue = motion_model(xTrue, u) - - # add noise to gps x-y - z = observation_model(xTrue) + GPS_NOISE @ np.random.randn(2, 1) - - # add noise to input - ud = u + INPUT_NOISE @ np.random.randn(2, 1) - - xd = motion_model(xd, ud) - - return xTrue, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0, 0], - [0, 1.0, 0, 0], - [0, 0, 1.0, 0], - [0, 0, 0, 0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT], - [1.0, 0.0]]) - - x = F @ x + B @ u - - return x - - -def observation_model(x): - H = np.array([ - [1, 0, 0, 0], - [0, 1, 0, 0] - ]) - - z = H @ x - - return z - - -def jacob_f(x, u): - """ - Jacobian of Motion Model - - motion model - x_{t+1} = x_t+v*dt*cos(yaw) - y_{t+1} = y_t+v*dt*sin(yaw) - yaw_{t+1} = yaw_t+omega*dt - v_{t+1} = v{t} - so - dx/dyaw = -v*dt*sin(yaw) - dx/dv = dt*cos(yaw) - dy/dyaw = v*dt*cos(yaw) - dy/dv = dt*sin(yaw) - """ - yaw = x[2, 0] - v = u[0, 0] - jF = np.array([ - [1.0, 0.0, -DT * v * math.sin(yaw), DT * math.cos(yaw)], - [0.0, 1.0, DT * v * math.cos(yaw), DT * math.sin(yaw)], - [0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 1.0]]) - - return jF - - -def jacob_h(): - # Jacobian of Observation Model - jH = np.array([ - [1, 0, 0, 0], - [0, 1, 0, 0] - ]) - - return jH - - -def ekf_estimation(xEst, PEst, z, u): - # Predict - xPred = motion_model(xEst, u) - jF = jacob_f(xEst, u) - PPred = jF @ PEst @ jF.T + Q - - # Update - jH = jacob_h() - zPred = observation_model(xPred) - y = z - zPred - S = jH @ PPred @ jH.T + R - K = PPred @ jH.T @ np.linalg.inv(S) - xEst = xPred + K @ y - PEst = (np.eye(len(xEst)) - K @ jH) @ PPred - return xEst, PEst - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # State Vector [x y yaw v]' - xEst = np.zeros((4, 1)) - xTrue = np.zeros((4, 1)) - PEst = np.eye(4) - - xDR = np.zeros((4, 1)) # Dead reckoning - - # history - hxEst = xEst - hxTrue = xTrue - hxDR = xTrue - hz = np.zeros((2, 1)) - - while SIM_TIME >= time: - time += DT - u = calc_input() - - xTrue, z, xDR, ud = observation(xTrue, xDR, u) - - xEst, PEst = ekf_estimation(xEst, PEst, z, ud) - - # store data history - hxEst = np.hstack((hxEst, xEst)) - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - hz = np.hstack((hz, z)) - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(hz[0, :], hz[1, :], ".g") - plt.plot(hxTrue[0, :].flatten(), - hxTrue[1, :].flatten(), "-b") - plt.plot(hxDR[0, :].flatten(), - hxDR[1, :].flatten(), "-k") - plt.plot(hxEst[0, :].flatten(), - hxEst[1, :].flatten(), "-r") - plot_covariance_ellipse(xEst[0, 0], xEst[1, 0], PEst) - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/Localization/histogram_filter/histogram_filter.py b/Localization/histogram_filter/histogram_filter.py deleted file mode 100644 index 17cfc2e14c7..00000000000 --- a/Localization/histogram_filter/histogram_filter.py +++ /dev/null @@ -1,265 +0,0 @@ -""" - -Histogram Filter 2D localization example - - -In this simulation, x,y are unknown, yaw is known. - -Initial position is not needed. - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import copy -import math - -import matplotlib.pyplot as plt -import matplotlib as mpl -import numpy as np -from scipy.ndimage import gaussian_filter -from scipy.stats import norm - -# Parameters -EXTEND_AREA = 10.0 # [m] grid map extended length -SIM_TIME = 50.0 # simulation time [s] -DT = 0.1 # time tick [s] -MAX_RANGE = 10.0 # maximum observation range -MOTION_STD = 1.0 # standard deviation for motion gaussian distribution -RANGE_STD = 3.0 # standard deviation for observation gaussian distribution - -# grid map param -XY_RESOLUTION = 0.5 # xy grid resolution -MIN_X = -15.0 -MIN_Y = -5.0 -MAX_X = 15.0 -MAX_Y = 25.0 - -# simulation parameters -NOISE_RANGE = 2.0 # [m] 1σ range noise parameter -NOISE_SPEED = 0.5 # [m/s] 1σ speed noise parameter - -show_animation = True - - -class GridMap: - - def __init__(self): - self.data = None - self.xy_resolution = None - self.min_x = None - self.min_y = None - self.max_x = None - self.max_y = None - self.x_w = None - self.y_w = None - self.dx = 0.0 # movement distance - self.dy = 0.0 # movement distance - - -def histogram_filter_localization(grid_map, u, z, yaw): - grid_map = motion_update(grid_map, u, yaw) - - grid_map = observation_update(grid_map, z, RANGE_STD) - - return grid_map - - -def calc_gaussian_observation_pdf(grid_map, z, iz, ix, iy, std): - # predicted range - x = ix * grid_map.xy_resolution + grid_map.min_x - y = iy * grid_map.xy_resolution + grid_map.min_y - d = math.hypot(x - z[iz, 1], y - z[iz, 2]) - - # likelihood - pdf = norm.pdf(d - z[iz, 0], 0.0, std) - - return pdf - - -def observation_update(grid_map, z, std): - for iz in range(z.shape[0]): - for ix in range(grid_map.x_w): - for iy in range(grid_map.y_w): - grid_map.data[ix][iy] *= calc_gaussian_observation_pdf( - grid_map, z, iz, ix, iy, std) - - grid_map = normalize_probability(grid_map) - - return grid_map - - -def calc_control_input(): - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - u = np.array([v, yaw_rate]).reshape(2, 1) - return u - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0, 0], - [0, 1.0, 0, 0], - [0, 0, 1.0, 0], - [0, 0, 0, 0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT], - [1.0, 0.0]]) - - x = F @ x + B @ u - - return x - - -def draw_heat_map(data, mx, my): - max_value = max([max(i_data) for i_data in data]) - plt.grid(False) - plt.pcolor(mx, my, data, vmax=max_value, cmap=mpl.colormaps["Blues"]) - plt.axis("equal") - - -def observation(xTrue, u, RFID): - xTrue = motion_model(xTrue, u) - - z = np.zeros((0, 3)) - - for i in range(len(RFID[:, 0])): - - dx = xTrue[0, 0] - RFID[i, 0] - dy = xTrue[1, 0] - RFID[i, 1] - d = math.hypot(dx, dy) - if d <= MAX_RANGE: - # add noise to range observation - dn = d + np.random.randn() * NOISE_RANGE - zi = np.array([dn, RFID[i, 0], RFID[i, 1]]) - z = np.vstack((z, zi)) - - # add noise to speed - ud = u[:, :] - ud[0] += np.random.randn() * NOISE_SPEED - - return xTrue, z, ud - - -def normalize_probability(grid_map): - sump = sum([sum(i_data) for i_data in grid_map.data]) - - for ix in range(grid_map.x_w): - for iy in range(grid_map.y_w): - grid_map.data[ix][iy] /= sump - - return grid_map - - -def init_grid_map(xy_resolution, min_x, min_y, max_x, max_y): - grid_map = GridMap() - - grid_map.xy_resolution = xy_resolution - grid_map.min_x = min_x - grid_map.min_y = min_y - grid_map.max_x = max_x - grid_map.max_y = max_y - grid_map.x_w = int(round((grid_map.max_x - grid_map.min_x) - / grid_map.xy_resolution)) - grid_map.y_w = int(round((grid_map.max_y - grid_map.min_y) - / grid_map.xy_resolution)) - - grid_map.data = [[1.0 for _ in range(grid_map.y_w)] - for _ in range(grid_map.x_w)] - grid_map = normalize_probability(grid_map) - - return grid_map - - -def map_shift(grid_map, x_shift, y_shift): - tmp_grid_map = copy.deepcopy(grid_map.data) - - for ix in range(grid_map.x_w): - for iy in range(grid_map.y_w): - nix = ix + x_shift - niy = iy + y_shift - - if 0 <= nix < grid_map.x_w and 0 <= niy < grid_map.y_w: - grid_map.data[ix + x_shift][iy + y_shift] =\ - tmp_grid_map[ix][iy] - - return grid_map - - -def motion_update(grid_map, u, yaw): - grid_map.dx += DT * math.cos(yaw) * u[0] - grid_map.dy += DT * math.sin(yaw) * u[0] - - x_shift = grid_map.dx // grid_map.xy_resolution - y_shift = grid_map.dy // grid_map.xy_resolution - - if abs(x_shift) >= 1.0 or abs(y_shift) >= 1.0: # map should be shifted - grid_map = map_shift(grid_map, int(x_shift[0]), int(y_shift[0])) - grid_map.dx -= x_shift * grid_map.xy_resolution - grid_map.dy -= y_shift * grid_map.xy_resolution - - # Add motion noise - grid_map.data = gaussian_filter(grid_map.data, sigma=MOTION_STD) - - return grid_map - - -def calc_grid_index(grid_map): - mx, my = np.mgrid[slice(grid_map.min_x - grid_map.xy_resolution / 2.0, - grid_map.max_x + grid_map.xy_resolution / 2.0, - grid_map.xy_resolution), - slice(grid_map.min_y - grid_map.xy_resolution / 2.0, - grid_map.max_y + grid_map.xy_resolution / 2.0, - grid_map.xy_resolution)] - - return mx, my - - -def main(): - print(__file__ + " start!!") - - # RF_ID positions [x, y] - RF_ID = np.array([[10.0, 0.0], - [10.0, 10.0], - [0.0, 15.0], - [-5.0, 20.0]]) - - time = 0.0 - - xTrue = np.zeros((4, 1)) - grid_map = init_grid_map(XY_RESOLUTION, MIN_X, MIN_Y, MAX_X, MAX_Y) - mx, my = calc_grid_index(grid_map) # for grid map visualization - - while SIM_TIME >= time: - time += DT - print(f"{time=:.1f}") - - u = calc_control_input() - - yaw = xTrue[2, 0] # Orientation is known - xTrue, z, ud = observation(xTrue, u, RF_ID) - - grid_map = histogram_filter_localization(grid_map, u, z, yaw) - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - draw_heat_map(grid_map.data, mx, my) - plt.plot(xTrue[0, :], xTrue[1, :], "xr") - plt.plot(RF_ID[:, 0], RF_ID[:, 1], ".k") - for i in range(z.shape[0]): - plt.plot([xTrue[0, 0], z[i, 1]], - [xTrue[1, 0], z[i, 2]], - "-k") - plt.title("Time[s]:" + str(time)[0: 4]) - plt.pause(0.1) - - print("Done") - - -if __name__ == '__main__': - main() diff --git a/Localization/particle_filter/particle_filter.py b/Localization/particle_filter/particle_filter.py deleted file mode 100644 index ba54a3d12b5..00000000000 --- a/Localization/particle_filter/particle_filter.py +++ /dev/null @@ -1,263 +0,0 @@ -""" - -Particle Filter localization sample - -author: Atsushi Sakai (@Atsushi_twi) - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import math - -import matplotlib.pyplot as plt -import numpy as np - -from utils.angle import rot_mat_2d - -# Estimation parameter of PF -Q = np.diag([0.2]) ** 2 # range error -R = np.diag([2.0, np.deg2rad(40.0)]) ** 2 # input error - -# Simulation parameter -Q_sim = np.diag([0.2]) ** 2 -R_sim = np.diag([1.0, np.deg2rad(30.0)]) ** 2 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] -MAX_RANGE = 20.0 # maximum observation range - -# Particle filter parameter -NP = 100 # Number of Particle -NTh = NP / 2.0 # Number of particle for re-sampling - -show_animation = True - - -def calc_input(): - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - u = np.array([[v, yaw_rate]]).T - return u - - -def observation(x_true, xd, u, rf_id): - x_true = motion_model(x_true, u) - - # add noise to gps x-y - z = np.zeros((0, 3)) - - for i in range(len(rf_id[:, 0])): - - dx = x_true[0, 0] - rf_id[i, 0] - dy = x_true[1, 0] - rf_id[i, 1] - d = math.hypot(dx, dy) - if d <= MAX_RANGE: - dn = d + np.random.randn() * Q_sim[0, 0] ** 0.5 # add noise - zi = np.array([[dn, rf_id[i, 0], rf_id[i, 1]]]) - z = np.vstack((z, zi)) - - # add noise to input - ud1 = u[0, 0] + np.random.randn() * R_sim[0, 0] ** 0.5 - ud2 = u[1, 0] + np.random.randn() * R_sim[1, 1] ** 0.5 - ud = np.array([[ud1, ud2]]).T - - xd = motion_model(xd, ud) - - return x_true, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0, 0], - [0, 1.0, 0, 0], - [0, 0, 1.0, 0], - [0, 0, 0, 0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT], - [1.0, 0.0]]) - - x = F.dot(x) + B.dot(u) - - return x - - -def gauss_likelihood(x, sigma): - p = 1.0 / math.sqrt(2.0 * math.pi * sigma ** 2) * \ - math.exp(-x ** 2 / (2 * sigma ** 2)) - - return p - - -def calc_covariance(x_est, px, pw): - """ - calculate covariance matrix - see ipynb doc - """ - cov = np.zeros((4, 4)) - n_particle = px.shape[1] - for i in range(n_particle): - dx = (px[:, i:i + 1] - x_est) - cov += pw[0, i] * dx @ dx.T - cov *= 1.0 / (1.0 - pw @ pw.T) - - return cov - - -def pf_localization(px, pw, z, u): - """ - Localization with Particle filter - """ - - for ip in range(NP): - x = np.array([px[:, ip]]).T - w = pw[0, ip] - - # Predict with random input sampling - ud1 = u[0, 0] + np.random.randn() * R[0, 0] ** 0.5 - ud2 = u[1, 0] + np.random.randn() * R[1, 1] ** 0.5 - ud = np.array([[ud1, ud2]]).T - x = motion_model(x, ud) - - # Calc Importance Weight - for i in range(len(z[:, 0])): - dx = x[0, 0] - z[i, 1] - dy = x[1, 0] - z[i, 2] - pre_z = math.hypot(dx, dy) - dz = pre_z - z[i, 0] - w = w * gauss_likelihood(dz, math.sqrt(Q[0, 0])) - - px[:, ip] = x[:, 0] - pw[0, ip] = w - - pw = pw / pw.sum() # normalize - - x_est = px.dot(pw.T) - p_est = calc_covariance(x_est, px, pw) - - N_eff = 1.0 / (pw.dot(pw.T))[0, 0] # Effective particle number - if N_eff < NTh: - px, pw = re_sampling(px, pw) - return x_est, p_est, px, pw - - -def re_sampling(px, pw): - """ - low variance re-sampling - """ - - w_cum = np.cumsum(pw) - base = np.arange(0.0, 1.0, 1 / NP) - re_sample_id = base + np.random.uniform(0, 1 / NP) - indexes = [] - ind = 0 - for ip in range(NP): - while re_sample_id[ip] > w_cum[ind]: - ind += 1 - indexes.append(ind) - - px = px[:, indexes] - pw = np.zeros((1, NP)) + 1.0 / NP # init weight - - return px, pw - - -def plot_covariance_ellipse(x_est, p_est): # pragma: no cover - p_xy = p_est[0:2, 0:2] - eig_val, eig_vec = np.linalg.eig(p_xy) - - if eig_val[0] >= eig_val[1]: - big_ind = 0 - small_ind = 1 - else: - big_ind = 1 - small_ind = 0 - - t = np.arange(0, 2 * math.pi + 0.1, 0.1) - - # eig_val[big_ind] or eiq_val[small_ind] were occasionally negative - # numbers extremely close to 0 (~10^-20), catch these cases and set the - # respective variable to 0 - try: - a = math.sqrt(eig_val[big_ind]) - except ValueError: - a = 0 - - try: - b = math.sqrt(eig_val[small_ind]) - except ValueError: - b = 0 - - x = [a * math.cos(it) for it in t] - y = [b * math.sin(it) for it in t] - angle = math.atan2(eig_vec[1, big_ind], eig_vec[0, big_ind]) - fx = rot_mat_2d(angle) @ np.array([[x, y]]) - px = np.array(fx[:, 0] + x_est[0, 0]).flatten() - py = np.array(fx[:, 1] + x_est[1, 0]).flatten() - plt.plot(px, py, "--r") - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # RF_ID positions [x, y] - rf_id = np.array([[10.0, 0.0], - [10.0, 10.0], - [0.0, 15.0], - [-5.0, 20.0]]) - - # State Vector [x y yaw v]' - x_est = np.zeros((4, 1)) - x_true = np.zeros((4, 1)) - - px = np.zeros((4, NP)) # Particle store - pw = np.zeros((1, NP)) + 1.0 / NP # Particle weight - x_dr = np.zeros((4, 1)) # Dead reckoning - - # history - h_x_est = x_est - h_x_true = x_true - h_x_dr = x_true - - while SIM_TIME >= time: - time += DT - u = calc_input() - - x_true, z, x_dr, ud = observation(x_true, x_dr, u, rf_id) - - x_est, PEst, px, pw = pf_localization(px, pw, z, ud) - - # store data history - h_x_est = np.hstack((h_x_est, x_est)) - h_x_dr = np.hstack((h_x_dr, x_dr)) - h_x_true = np.hstack((h_x_true, x_true)) - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - for i in range(len(z[:, 0])): - plt.plot([x_true[0, 0], z[i, 1]], [x_true[1, 0], z[i, 2]], "-k") - plt.plot(rf_id[:, 0], rf_id[:, 1], "*k") - plt.plot(px[0, :], px[1, :], ".r") - plt.plot(np.array(h_x_true[0, :]).flatten(), - np.array(h_x_true[1, :]).flatten(), "-b") - plt.plot(np.array(h_x_dr[0, :]).flatten(), - np.array(h_x_dr[1, :]).flatten(), "-k") - plt.plot(np.array(h_x_est[0, :]).flatten(), - np.array(h_x_est[1, :]).flatten(), "-r") - plot_covariance_ellipse(x_est, PEst) - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/Localization/unscented_kalman_filter/unscented_kalman_filter.py b/Localization/unscented_kalman_filter/unscented_kalman_filter.py deleted file mode 100644 index 4af748ec71e..00000000000 --- a/Localization/unscented_kalman_filter/unscented_kalman_filter.py +++ /dev/null @@ -1,264 +0,0 @@ -""" - -Unscented kalman filter (UKF) localization sample - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import math - -import matplotlib.pyplot as plt -import numpy as np -import scipy.linalg - -from utils.angle import rot_mat_2d - -# Covariance for UKF simulation -Q = np.diag([ - 0.1, # variance of location on x-axis - 0.1, # variance of location on y-axis - np.deg2rad(1.0), # variance of yaw angle - 1.0 # variance of velocity -]) ** 2 # predict state covariance -R = np.diag([1.0, 1.0]) ** 2 # Observation x,y position covariance - -# Simulation parameter -INPUT_NOISE = np.diag([1.0, np.deg2rad(30.0)]) ** 2 -GPS_NOISE = np.diag([0.5, 0.5]) ** 2 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] - -# UKF Parameter -ALPHA = 0.001 -BETA = 2 -KAPPA = 0 - -show_animation = True - - -def calc_input(): - v = 1.0 # [m/s] - yawRate = 0.1 # [rad/s] - u = np.array([[v, yawRate]]).T - return u - - -def observation(xTrue, xd, u): - xTrue = motion_model(xTrue, u) - - # add noise to gps x-y - z = observation_model(xTrue) + GPS_NOISE @ np.random.randn(2, 1) - - # add noise to input - ud = u + INPUT_NOISE @ np.random.randn(2, 1) - - xd = motion_model(xd, ud) - - return xTrue, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0, 0], - [0, 1.0, 0, 0], - [0, 0, 1.0, 0], - [0, 0, 0, 0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT], - [1.0, 0.0]]) - - x = F @ x + B @ u - - return x - - -def observation_model(x): - H = np.array([ - [1, 0, 0, 0], - [0, 1, 0, 0] - ]) - - z = H @ x - - return z - - -def generate_sigma_points(xEst, PEst, gamma): - sigma = xEst - Psqrt = scipy.linalg.sqrtm(PEst) - n = len(xEst[:, 0]) - # Positive direction - for i in range(n): - sigma = np.hstack((sigma, xEst + gamma * Psqrt[:, i:i + 1])) - - # Negative direction - for i in range(n): - sigma = np.hstack((sigma, xEst - gamma * Psqrt[:, i:i + 1])) - - return sigma - - -def predict_sigma_motion(sigma, u): - """ - Sigma Points prediction with motion model - """ - for i in range(sigma.shape[1]): - sigma[:, i:i + 1] = motion_model(sigma[:, i:i + 1], u) - - return sigma - - -def predict_sigma_observation(sigma): - """ - Sigma Points prediction with observation model - """ - for i in range(sigma.shape[1]): - sigma[0:2, i] = observation_model(sigma[:, i]) - - sigma = sigma[0:2, :] - - return sigma - - -def calc_sigma_covariance(x, sigma, wc, Pi): - nSigma = sigma.shape[1] - d = sigma - x[0:sigma.shape[0]] - P = Pi - for i in range(nSigma): - P = P + wc[0, i] * d[:, i:i + 1] @ d[:, i:i + 1].T - return P - - -def calc_pxz(sigma, x, z_sigma, zb, wc): - nSigma = sigma.shape[1] - dx = sigma - x - dz = z_sigma - zb[0:2] - P = np.zeros((dx.shape[0], dz.shape[0])) - - for i in range(nSigma): - P = P + wc[0, i] * dx[:, i:i + 1] @ dz[:, i:i + 1].T - - return P - - -def ukf_estimation(xEst, PEst, z, u, wm, wc, gamma): - # Predict - sigma = generate_sigma_points(xEst, PEst, gamma) - sigma = predict_sigma_motion(sigma, u) - xPred = (wm @ sigma.T).T - PPred = calc_sigma_covariance(xPred, sigma, wc, Q) - - # Update - zPred = observation_model(xPred) - y = z - zPred - sigma = generate_sigma_points(xPred, PPred, gamma) - zb = (wm @ sigma.T).T - z_sigma = predict_sigma_observation(sigma) - st = calc_sigma_covariance(zb, z_sigma, wc, R) - Pxz = calc_pxz(sigma, xPred, z_sigma, zb, wc) - K = Pxz @ np.linalg.inv(st) - xEst = xPred + K @ y - PEst = PPred - K @ st @ K.T - - return xEst, PEst - - -def plot_covariance_ellipse(xEst, PEst): # pragma: no cover - Pxy = PEst[0:2, 0:2] - eigval, eigvec = np.linalg.eig(Pxy) - - if eigval[0] >= eigval[1]: - bigind = 0 - smallind = 1 - else: - bigind = 1 - smallind = 0 - - t = np.arange(0, 2 * math.pi + 0.1, 0.1) - a = math.sqrt(eigval[bigind]) - b = math.sqrt(eigval[smallind]) - x = [a * math.cos(it) for it in t] - y = [b * math.sin(it) for it in t] - angle = math.atan2(eigvec[1, bigind], eigvec[0, bigind]) - fx = rot_mat_2d(angle) @ np.array([x, y]) - px = np.array(fx[0, :] + xEst[0, 0]).flatten() - py = np.array(fx[1, :] + xEst[1, 0]).flatten() - plt.plot(px, py, "--r") - - -def setup_ukf(nx): - lamb = ALPHA ** 2 * (nx + KAPPA) - nx - # calculate weights - wm = [lamb / (lamb + nx)] - wc = [(lamb / (lamb + nx)) + (1 - ALPHA ** 2 + BETA)] - for i in range(2 * nx): - wm.append(1.0 / (2 * (nx + lamb))) - wc.append(1.0 / (2 * (nx + lamb))) - gamma = math.sqrt(nx + lamb) - - wm = np.array([wm]) - wc = np.array([wc]) - - return wm, wc, gamma - - -def main(): - print(__file__ + " start!!") - - nx = 4 # State Vector [x y yaw v]' - xEst = np.zeros((nx, 1)) - xTrue = np.zeros((nx, 1)) - PEst = np.eye(nx) - xDR = np.zeros((nx, 1)) # Dead reckoning - - wm, wc, gamma = setup_ukf(nx) - - # history - hxEst = xEst - hxTrue = xTrue - hxDR = xTrue - hz = np.zeros((2, 1)) - - time = 0.0 - - while SIM_TIME >= time: - time += DT - u = calc_input() - - xTrue, z, xDR, ud = observation(xTrue, xDR, u) - - xEst, PEst = ukf_estimation(xEst, PEst, z, ud, wm, wc, gamma) - - # store data history - hxEst = np.hstack((hxEst, xEst)) - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - hz = np.hstack((hz, z)) - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(hz[0, :], hz[1, :], ".g") - plt.plot(np.array(hxTrue[0, :]).flatten(), - np.array(hxTrue[1, :]).flatten(), "-b") - plt.plot(np.array(hxDR[0, :]).flatten(), - np.array(hxDR[1, :]).flatten(), "-k") - plt.plot(np.array(hxEst[0, :]).flatten(), - np.array(hxEst[1, :]).flatten(), "-r") - plot_covariance_ellipse(xEst, PEst) - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/Mapping/DistanceMap/distance_map.py b/Mapping/DistanceMap/distance_map.py deleted file mode 100644 index 0dcc7380c54..00000000000 --- a/Mapping/DistanceMap/distance_map.py +++ /dev/null @@ -1,202 +0,0 @@ -""" -Distance Map - -author: Wang Zheng (@Aglargil) - -Ref: - -- [Distance Map] -(https://cs.brown.edu/people/pfelzens/papers/dt-final.pdf) -""" - -import numpy as np -import matplotlib.pyplot as plt -import scipy - -INF = 1e20 -ENABLE_PLOT = True - - -def compute_sdf_scipy(obstacles): - """ - Compute the signed distance field (SDF) from a boolean field using scipy. - This function has the same functionality as compute_sdf. - However, by using scipy.ndimage.distance_transform_edt, it can compute much faster. - - Example: 500×500 map - • compute_sdf: 3 sec - • compute_sdf_scipy: 0.05 sec - - Parameters - ---------- - obstacles : array_like - A 2D boolean array where '1' represents obstacles and '0' represents free space. - - Returns - ------- - array_like - A 2D array representing the signed distance field, where positive values indicate distance - to the nearest obstacle, and negative values indicate distance to the nearest free space. - """ - # distance_transform_edt use '0' as obstacles, so we need to convert the obstacles to '0' - a = scipy.ndimage.distance_transform_edt(obstacles == 0) - b = scipy.ndimage.distance_transform_edt(obstacles == 1) - return a - b - - -def compute_udf_scipy(obstacles): - """ - Compute the unsigned distance field (UDF) from a boolean field using scipy. - This function has the same functionality as compute_udf. - However, by using scipy.ndimage.distance_transform_edt, it can compute much faster. - - Example: 500×500 map - • compute_udf: 1.5 sec - • compute_udf_scipy: 0.02 sec - - Parameters - ---------- - obstacles : array_like - A 2D boolean array where '1' represents obstacles and '0' represents free space. - - Returns - ------- - array_like - A 2D array of distances from the nearest obstacle, with the same dimensions as `bool_field`. - """ - return scipy.ndimage.distance_transform_edt(obstacles == 0) - - -def compute_sdf(obstacles): - """ - Compute the signed distance field (SDF) from a boolean field. - - Parameters - ---------- - obstacles : array_like - A 2D boolean array where '1' represents obstacles and '0' represents free space. - - Returns - ------- - array_like - A 2D array representing the signed distance field, where positive values indicate distance - to the nearest obstacle, and negative values indicate distance to the nearest free space. - """ - a = compute_udf(obstacles) - b = compute_udf(obstacles == 0) - return a - b - - -def compute_udf(obstacles): - """ - Compute the unsigned distance field (UDF) from a boolean field. - - Parameters - ---------- - obstacles : array_like - A 2D boolean array where '1' represents obstacles and '0' represents free space. - - Returns - ------- - array_like - A 2D array of distances from the nearest obstacle, with the same dimensions as `bool_field`. - """ - edt = obstacles.copy() - if not np.all(np.isin(edt, [0, 1])): - raise ValueError("Input array should only contain 0 and 1") - edt = np.where(edt == 0, INF, edt) - edt = np.where(edt == 1, 0, edt) - for row in range(len(edt)): - dt(edt[row]) - edt = edt.T - for row in range(len(edt)): - dt(edt[row]) - edt = edt.T - return np.sqrt(edt) - - -def dt(d): - """ - Compute 1D distance transform under the squared Euclidean distance - - Parameters - ---------- - d : array_like - Input array containing the distances. - - Returns: - -------- - d : array_like - The transformed array with computed distances. - """ - v = np.zeros(len(d) + 1) - z = np.zeros(len(d) + 1) - k = 0 - v[0] = 0 - z[0] = -INF - z[1] = INF - for q in range(1, len(d)): - s = ((d[q] + q * q) - (d[int(v[k])] + v[k] * v[k])) / (2 * q - 2 * v[k]) - while s <= z[k]: - k = k - 1 - s = ((d[q] + q * q) - (d[int(v[k])] + v[k] * v[k])) / (2 * q - 2 * v[k]) - k = k + 1 - v[k] = q - z[k] = s - z[k + 1] = INF - k = 0 - for q in range(len(d)): - while z[k + 1] < q: - k = k + 1 - dx = q - v[k] - d[q] = dx * dx + d[int(v[k])] - - -def main(): - obstacles = np.array( - [ - [1, 0, 0, 0, 0], - [0, 1, 1, 1, 0], - [0, 1, 1, 1, 0], - [0, 0, 1, 1, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - ] - ) - - # Compute the signed distance field - sdf = compute_sdf(obstacles) - udf = compute_udf(obstacles) - - if ENABLE_PLOT: - _, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5)) - - obstacles_plot = ax1.imshow(obstacles, cmap="binary") - ax1.set_title("Obstacles") - ax1.set_xlabel("x") - ax1.set_ylabel("y") - plt.colorbar(obstacles_plot, ax=ax1) - - udf_plot = ax2.imshow(udf, cmap="viridis") - ax2.set_title("Unsigned Distance Field") - ax2.set_xlabel("x") - ax2.set_ylabel("y") - plt.colorbar(udf_plot, ax=ax2) - - sdf_plot = ax3.imshow(sdf, cmap="RdBu") - ax3.set_title("Signed Distance Field") - ax3.set_xlabel("x") - ax3.set_ylabel("y") - plt.colorbar(sdf_plot, ax=ax3) - - plt.tight_layout() - plt.show() - - -if __name__ == "__main__": - main() diff --git a/Mapping/__init__.py b/Mapping/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Mapping/circle_fitting/circle_fitting.py b/Mapping/circle_fitting/circle_fitting.py deleted file mode 100644 index 2eba5501273..00000000000 --- a/Mapping/circle_fitting/circle_fitting.py +++ /dev/null @@ -1,141 +0,0 @@ -""" - -Object shape recognition with circle fitting - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import matplotlib.pyplot as plt -import math -import random -import numpy as np - -show_animation = True - - -def circle_fitting(x, y): - """ - Circle Fitting with least squared - input: point x-y positions - output cxe x center position - cye y center position - re radius of circle - error: prediction error - """ - - sumx = sum(x) - sumy = sum(y) - sumx2 = sum([ix ** 2 for ix in x]) - sumy2 = sum([iy ** 2 for iy in y]) - sumxy = sum([ix * iy for (ix, iy) in zip(x, y)]) - - F = np.array([[sumx2, sumxy, sumx], - [sumxy, sumy2, sumy], - [sumx, sumy, len(x)]]) - - G = np.array([[-sum([ix ** 3 + ix * iy ** 2 for (ix, iy) in zip(x, y)])], - [-sum([ix ** 2 * iy + iy ** 3 for (ix, iy) in zip(x, y)])], - [-sum([ix ** 2 + iy ** 2 for (ix, iy) in zip(x, y)])]]) - - T = np.linalg.inv(F).dot(G) - - cxe = float(T[0, 0] / -2) - cye = float(T[1, 0] / -2) - re = math.sqrt(cxe**2 + cye**2 - T[2, 0]) - - error = sum([np.hypot(cxe - ix, cye - iy) - re for (ix, iy) in zip(x, y)]) - - return (cxe, cye, re, error) - - -def get_sample_points(cx, cy, cr, angle_reso): - x, y, angle, r = [], [], [], [] - - # points sampling - for theta in np.arange(0.0, 2.0 * math.pi, angle_reso): - nx = cx + cr * math.cos(theta) - ny = cy + cr * math.sin(theta) - nangle = math.atan2(ny, nx) - nr = math.hypot(nx, ny) * random.uniform(0.95, 1.05) - - x.append(nx) - y.append(ny) - angle.append(nangle) - r.append(nr) - - # ray casting filter - rx, ry = ray_casting_filter(x, y, angle, r, angle_reso) - - return rx, ry - - -def ray_casting_filter(xl, yl, thetal, rangel, angle_reso): - rx, ry = [], [] - rangedb = [float("inf") for _ in range( - int(math.floor((math.pi * 2.0) / angle_reso)) + 1)] - - for i, _ in enumerate(thetal): - angleid = math.floor(thetal[i] / angle_reso) - - if rangedb[angleid] > rangel[i]: - rangedb[angleid] = rangel[i] - - for i, _ in enumerate(rangedb): - t = i * angle_reso - if rangedb[i] != float("inf"): - rx.append(rangedb[i] * math.cos(t)) - ry.append(rangedb[i] * math.sin(t)) - - return rx, ry - - -def plot_circle(x, y, size, color="-b"): # pragma: no cover - deg = list(range(0, 360, 5)) - deg.append(0) - xl = [x + size * math.cos(np.deg2rad(d)) for d in deg] - yl = [y + size * math.sin(np.deg2rad(d)) for d in deg] - plt.plot(xl, yl, color) - - -def main(): - - # simulation parameters - simtime = 15.0 # simulation time - dt = 1.0 # time tick - - cx = -2.0 # initial x position of obstacle - cy = -8.0 # initial y position of obstacle - cr = 1.0 # obstacle radious - theta = np.deg2rad(30.0) # obstacle moving direction - angle_reso = np.deg2rad(3.0) # sensor angle resolution - - time = 0.0 - while time <= simtime: - time += dt - - cx += math.cos(theta) - cy += math.cos(theta) - - x, y = get_sample_points(cx, cy, cr, angle_reso) - - ex, ey, er, error = circle_fitting(x, y) - print("Error:", error) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.axis("equal") - plt.plot(0.0, 0.0, "*r") - plot_circle(cx, cy, cr) - plt.plot(x, y, "xr") - plot_circle(ex, ey, er, "-r") - plt.pause(dt) - - print("Done") - - -if __name__ == '__main__': - main() diff --git a/Mapping/gaussian_grid_map/gaussian_grid_map.py b/Mapping/gaussian_grid_map/gaussian_grid_map.py deleted file mode 100644 index b7664f1acbb..00000000000 --- a/Mapping/gaussian_grid_map/gaussian_grid_map.py +++ /dev/null @@ -1,86 +0,0 @@ -""" - -2D gaussian grid map sample - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math -import numpy as np -import matplotlib.pyplot as plt -from scipy.stats import norm - -EXTEND_AREA = 10.0 # [m] grid map extention length - -show_animation = True - - -def generate_gaussian_grid_map(ox, oy, xyreso, std): - - minx, miny, maxx, maxy, xw, yw = calc_grid_map_config(ox, oy, xyreso) - - gmap = [[0.0 for i in range(yw)] for i in range(xw)] - - for ix in range(xw): - for iy in range(yw): - - x = ix * xyreso + minx - y = iy * xyreso + miny - - # Search minimum distance - mindis = float("inf") - for (iox, ioy) in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if mindis >= d: - mindis = d - - pdf = (1.0 - norm.cdf(mindis, 0.0, std)) - gmap[ix][iy] = pdf - - return gmap, minx, maxx, miny, maxy - - -def calc_grid_map_config(ox, oy, xyreso): - minx = round(min(ox) - EXTEND_AREA / 2.0) - miny = round(min(oy) - EXTEND_AREA / 2.0) - maxx = round(max(ox) + EXTEND_AREA / 2.0) - maxy = round(max(oy) + EXTEND_AREA / 2.0) - xw = int(round((maxx - minx) / xyreso)) - yw = int(round((maxy - miny) / xyreso)) - - return minx, miny, maxx, maxy, xw, yw - - -def draw_heatmap(data, minx, maxx, miny, maxy, xyreso): - x, y = np.mgrid[slice(minx - xyreso / 2.0, maxx + xyreso / 2.0, xyreso), - slice(miny - xyreso / 2.0, maxy + xyreso / 2.0, xyreso)] - plt.pcolor(x, y, data, vmax=1.0, cmap=plt.cm.Blues) - plt.axis("equal") - - -def main(): - print(__file__ + " start!!") - - xyreso = 0.5 # xy grid resolution - STD = 5.0 # standard diviation for gaussian distribution - - for i in range(5): - ox = (np.random.rand(4) - 0.5) * 10.0 - oy = (np.random.rand(4) - 0.5) * 10.0 - gmap, minx, maxx, miny, maxy = generate_gaussian_grid_map( - ox, oy, xyreso, STD) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - draw_heatmap(gmap, minx, maxx, miny, maxy, xyreso) - plt.plot(ox, oy, "xr") - plt.plot(0.0, 0.0, "ob") - plt.pause(1.0) - - -if __name__ == '__main__': - main() diff --git a/Mapping/grid_map_lib/__init__.py b/Mapping/grid_map_lib/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Mapping/grid_map_lib/grid_map_lib.py b/Mapping/grid_map_lib/grid_map_lib.py deleted file mode 100644 index d08d8ec5ba4..00000000000 --- a/Mapping/grid_map_lib/grid_map_lib.py +++ /dev/null @@ -1,312 +0,0 @@ -""" - -Grid map library in python - -author: Atsushi Sakai - -""" -from functools import total_ordering -import matplotlib.pyplot as plt -import numpy as np - - -@total_ordering -class FloatGrid: - - def __init__(self, init_val=0.0): - self.data = init_val - - def get_float_data(self): - return self.data - - def __eq__(self, other): - if not isinstance(other, FloatGrid): - return NotImplemented - return self.get_float_data() == other.get_float_data() - - def __lt__(self, other): - if not isinstance(other, FloatGrid): - return NotImplemented - return self.get_float_data() < other.get_float_data() - - -class GridMap: - """ - GridMap class - """ - - def __init__(self, width, height, resolution, - center_x, center_y, init_val=FloatGrid(0.0)): - """__init__ - - :param width: number of grid for width - :param height: number of grid for height - :param resolution: grid resolution [m] - :param center_x: center x position [m] - :param center_y: center y position [m] - :param init_val: initial value for all grid - """ - self.width = width - self.height = height - self.resolution = resolution - self.center_x = center_x - self.center_y = center_y - - self.left_lower_x = self.center_x - self.width / 2.0 * self.resolution - self.left_lower_y = self.center_y - self.height / 2.0 * self.resolution - - self.n_data = self.width * self.height - self.data = [init_val] * self.n_data - self.data_type = type(init_val) - - def get_value_from_xy_index(self, x_ind, y_ind): - """get_value_from_xy_index - - when the index is out of grid map area, return None - - :param x_ind: x index - :param y_ind: y index - """ - - grid_ind = self.calc_grid_index_from_xy_index(x_ind, y_ind) - - if 0 <= grid_ind < self.n_data: - return self.data[grid_ind] - else: - return None - - def get_xy_index_from_xy_pos(self, x_pos, y_pos): - """get_xy_index_from_xy_pos - - :param x_pos: x position [m] - :param y_pos: y position [m] - """ - x_ind = self.calc_xy_index_from_position( - x_pos, self.left_lower_x, self.width) - y_ind = self.calc_xy_index_from_position( - y_pos, self.left_lower_y, self.height) - - return x_ind, y_ind - - def set_value_from_xy_pos(self, x_pos, y_pos, val): - """set_value_from_xy_pos - - return bool flag, which means setting value is succeeded or not - - :param x_pos: x position [m] - :param y_pos: y position [m] - :param val: grid value - """ - - x_ind, y_ind = self.get_xy_index_from_xy_pos(x_pos, y_pos) - - if (not x_ind) or (not y_ind): - return False # NG - - flag = self.set_value_from_xy_index(x_ind, y_ind, val) - - return flag - - def set_value_from_xy_index(self, x_ind, y_ind, val): - """set_value_from_xy_index - - return bool flag, which means setting value is succeeded or not - - :param x_ind: x index - :param y_ind: y index - :param val: grid value - """ - - if (x_ind is None) or (y_ind is None): - return False, False - - grid_ind = int(y_ind * self.width + x_ind) - - if 0 <= grid_ind < self.n_data and isinstance(val, self.data_type): - self.data[grid_ind] = val - return True # OK - else: - return False # NG - - def set_value_from_polygon(self, pol_x, pol_y, val, inside=True): - """set_value_from_polygon - - Setting value inside or outside polygon - - :param pol_x: x position list for a polygon - :param pol_y: y position list for a polygon - :param val: grid value - :param inside: setting data inside or outside - """ - - # making ring polygon - if (pol_x[0] != pol_x[-1]) or (pol_y[0] != pol_y[-1]): - np.append(pol_x, pol_x[0]) - np.append(pol_y, pol_y[0]) - - # setting value for all grid - for x_ind in range(self.width): - for y_ind in range(self.height): - x_pos, y_pos = self.calc_grid_central_xy_position_from_xy_index( - x_ind, y_ind) - - flag = self.check_inside_polygon(x_pos, y_pos, pol_x, pol_y) - - if flag is inside: - self.set_value_from_xy_index(x_ind, y_ind, val) - - def calc_grid_index_from_xy_index(self, x_ind, y_ind): - grid_ind = int(y_ind * self.width + x_ind) - return grid_ind - - def calc_xy_index_from_grid_index(self, grid_ind): - y_ind, x_ind = divmod(grid_ind, self.width) - return x_ind, y_ind - - def calc_grid_index_from_xy_pos(self, x_pos, y_pos): - """get_xy_index_from_xy_pos - - :param x_pos: x position [m] - :param y_pos: y position [m] - """ - x_ind = self.calc_xy_index_from_position( - x_pos, self.left_lower_x, self.width) - y_ind = self.calc_xy_index_from_position( - y_pos, self.left_lower_y, self.height) - - return self.calc_grid_index_from_xy_index(x_ind, y_ind) - - def calc_grid_central_xy_position_from_grid_index(self, grid_ind): - x_ind, y_ind = self.calc_xy_index_from_grid_index(grid_ind) - return self.calc_grid_central_xy_position_from_xy_index(x_ind, y_ind) - - def calc_grid_central_xy_position_from_xy_index(self, x_ind, y_ind): - x_pos = self.calc_grid_central_xy_position_from_index( - x_ind, self.left_lower_x) - y_pos = self.calc_grid_central_xy_position_from_index( - y_ind, self.left_lower_y) - - return x_pos, y_pos - - def calc_grid_central_xy_position_from_index(self, index, lower_pos): - return lower_pos + index * self.resolution + self.resolution / 2.0 - - def calc_xy_index_from_position(self, pos, lower_pos, max_index): - ind = int(np.floor((pos - lower_pos) / self.resolution)) - if 0 <= ind <= max_index: - return ind - else: - return None - - def check_occupied_from_xy_index(self, x_ind, y_ind, occupied_val): - - val = self.get_value_from_xy_index(x_ind, y_ind) - - if val is None or val >= occupied_val: - return True - else: - return False - - def expand_grid(self, occupied_val=FloatGrid(1.0)): - x_inds, y_inds, values = [], [], [] - - for ix in range(self.width): - for iy in range(self.height): - if self.check_occupied_from_xy_index(ix, iy, occupied_val): - x_inds.append(ix) - y_inds.append(iy) - values.append(self.get_value_from_xy_index(ix, iy)) - - for (ix, iy, value) in zip(x_inds, y_inds, values): - self.set_value_from_xy_index(ix + 1, iy, val=value) - self.set_value_from_xy_index(ix, iy + 1, val=value) - self.set_value_from_xy_index(ix + 1, iy + 1, val=value) - self.set_value_from_xy_index(ix - 1, iy, val=value) - self.set_value_from_xy_index(ix, iy - 1, val=value) - self.set_value_from_xy_index(ix - 1, iy - 1, val=value) - - @staticmethod - def check_inside_polygon(iox, ioy, x, y): - - n_point = len(x) - 1 - inside = False - for i1 in range(n_point): - i2 = (i1 + 1) % (n_point + 1) - - if x[i1] >= x[i2]: - min_x, max_x = x[i2], x[i1] - else: - min_x, max_x = x[i1], x[i2] - if not min_x <= iox < max_x: - continue - - tmp1 = (y[i2] - y[i1]) / (x[i2] - x[i1]) - if (y[i1] + tmp1 * (iox - x[i1]) - ioy) > 0.0: - inside = not inside - - return inside - - def print_grid_map_info(self): - print("width:", self.width) - print("height:", self.height) - print("resolution:", self.resolution) - print("center_x:", self.center_x) - print("center_y:", self.center_y) - print("left_lower_x:", self.left_lower_x) - print("left_lower_y:", self.left_lower_y) - print("n_data:", self.n_data) - - def plot_grid_map(self, ax=None): - float_data_array = np.array([d.get_float_data() for d in self.data]) - grid_data = np.reshape(float_data_array, (self.height, self.width)) - if not ax: - fig, ax = plt.subplots() - heat_map = ax.pcolor(grid_data, cmap="Blues", vmin=0.0, vmax=1.0) - plt.axis("equal") - - return heat_map - - -def polygon_set_demo(): - ox = [0.0, 4.35, 20.0, 50.0, 100.0, 130.0, 40.0] - oy = [0.0, -4.15, -20.0, 0.0, 30.0, 60.0, 80.0] - - grid_map = GridMap(600, 290, 0.7, 60.0, 30.5) - - grid_map.set_value_from_polygon(ox, oy, FloatGrid(1.0), inside=False) - - grid_map.plot_grid_map() - - plt.axis("equal") - plt.grid(True) - - -def position_set_demo(): - grid_map = GridMap(100, 120, 0.5, 10.0, -0.5) - - grid_map.set_value_from_xy_pos(10.1, -1.1, FloatGrid(1.0)) - grid_map.set_value_from_xy_pos(10.1, -0.1, FloatGrid(1.0)) - grid_map.set_value_from_xy_pos(10.1, 1.1, FloatGrid(1.0)) - grid_map.set_value_from_xy_pos(11.1, 0.1, FloatGrid(1.0)) - grid_map.set_value_from_xy_pos(10.1, 0.1, FloatGrid(1.0)) - grid_map.set_value_from_xy_pos(9.1, 0.1, FloatGrid(1.0)) - - grid_map.plot_grid_map() - - plt.axis("equal") - plt.grid(True) - - -def main(): - print("start!!") - - position_set_demo() - polygon_set_demo() - - plt.show() - - print("done!!") - - -if __name__ == '__main__': - main() diff --git a/Mapping/kmeans_clustering/kmeans_clustering.py b/Mapping/kmeans_clustering/kmeans_clustering.py deleted file mode 100644 index e18960e9903..00000000000 --- a/Mapping/kmeans_clustering/kmeans_clustering.py +++ /dev/null @@ -1,149 +0,0 @@ -""" - -Object clustering with k-means algorithm - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math -import matplotlib.pyplot as plt -import random - -# k means parameters -MAX_LOOP = 10 -DCOST_TH = 0.1 -show_animation = True - - -def kmeans_clustering(rx, ry, nc): - clusters = Clusters(rx, ry, nc) - clusters.calc_centroid() - - pre_cost = float("inf") - for loop in range(MAX_LOOP): - print("loop:", loop) - cost = clusters.update_clusters() - clusters.calc_centroid() - - d_cost = abs(cost - pre_cost) - if d_cost < DCOST_TH: - break - pre_cost = cost - - return clusters - - -class Clusters: - - def __init__(self, x, y, n_label): - self.x = x - self.y = y - self.n_data = len(self.x) - self.n_label = n_label - self.labels = [random.randint(0, n_label - 1) - for _ in range(self.n_data)] - self.center_x = [0.0 for _ in range(n_label)] - self.center_y = [0.0 for _ in range(n_label)] - - def plot_cluster(self): - for label in set(self.labels): - x, y = self._get_labeled_x_y(label) - plt.plot(x, y, ".") - - def calc_centroid(self): - for label in set(self.labels): - x, y = self._get_labeled_x_y(label) - n_data = len(x) - self.center_x[label] = sum(x) / n_data - self.center_y[label] = sum(y) / n_data - - def update_clusters(self): - cost = 0.0 - - for ip in range(self.n_data): - px = self.x[ip] - py = self.y[ip] - - dx = [icx - px for icx in self.center_x] - dy = [icy - py for icy in self.center_y] - - dist_list = [math.hypot(idx, idy) for (idx, idy) in zip(dx, dy)] - min_dist = min(dist_list) - min_id = dist_list.index(min_dist) - self.labels[ip] = min_id - cost += min_dist - - return cost - - def _get_labeled_x_y(self, target_label): - x = [self.x[i] for i, label in enumerate(self.labels) if label == target_label] - y = [self.y[i] for i, label in enumerate(self.labels) if label == target_label] - return x, y - - -def calc_raw_data(cx, cy, n_points, rand_d): - rx, ry = [], [] - - for (icx, icy) in zip(cx, cy): - for _ in range(n_points): - rx.append(icx + rand_d * (random.random() - 0.5)) - ry.append(icy + rand_d * (random.random() - 0.5)) - - return rx, ry - - -def update_positions(cx, cy): - # object moving parameters - DX1 = 0.4 - DY1 = 0.5 - DX2 = -0.3 - DY2 = -0.5 - - cx[0] += DX1 - cy[0] += DY1 - cx[1] += DX2 - cy[1] += DY2 - - return cx, cy - - -def main(): - print(__file__ + " start!!") - - cx = [0.0, 8.0] - cy = [0.0, 8.0] - n_points = 10 - rand_d = 3.0 - n_cluster = 2 - sim_time = 15.0 - dt = 1.0 - time = 0.0 - - while time <= sim_time: - print("Time:", time) - time += dt - - # objects moving simulation - cx, cy = update_positions(cx, cy) - raw_x, raw_y = calc_raw_data(cx, cy, n_points, rand_d) - - clusters = kmeans_clustering(raw_x, raw_y, n_cluster) - - # for animation - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - clusters.plot_cluster() - plt.plot(cx, cy, "or") - plt.xlim(-2.0, 10.0) - plt.ylim(-2.0, 10.0) - plt.pause(dt) - - print("Done") - - -if __name__ == '__main__': - main() diff --git a/Mapping/lidar_to_grid_map/lidar01.csv b/Mapping/lidar_to_grid_map/lidar01.csv deleted file mode 100644 index 1f6b3f5cd9f..00000000000 --- a/Mapping/lidar_to_grid_map/lidar01.csv +++ /dev/null @@ -1,154 +0,0 @@ -0.008450416037156572,0.5335 -0.046902201120156306,0.5345 -0.08508127850753233,0.537 -0.1979822644959155,0.2605 -0.21189035697274505,0.2625 -0.2587960806200922,0.26475 -0.3043382657893199,0.2675 -0.34660795861105775,0.27075 -0.43632879047139106,0.59 -0.4739624524675188,0.60025 -0.5137777760286397,0.611 -0.5492297764597742,0.6265 -0.5895905154121426,0.64 -0.6253152235389017,0.6565 -0.6645851317087743,0.676 -0.6997644244442851,0.6975 -0.7785769484796541,0.3345 -0.7772134100015329,0.74575 -0.8652979956881222,0.3315 -0.8996591653367609,0.31775 -0.9397471965935056,0.31275 -0.9847439663714841,0.31125 -1.0283771976713423,0.31325 -1.0641019057981014,0.31975 -1.1009174447073562,0.3335 -1.2012738766970301,0.92275 -1.2397256617800307,0.95325 -1.2779047391674068,0.9865 -1.316629231946031,1.01775 -1.3561718478115274,1.011 -1.3948963405901518,1.0055 -1.4330754179775278,1.00225 -1.4731634492342724,0.99975 -1.5113425266216485,0.9975 -1.5517032655740168,1.001 -1.5896096352657691,1.00275 -1.6288795434356418,1.008 -1.6684221593011381,1.0135 -1.7066012366885142,1.022 -1.7453257294671385,1.02875 -1.7862318838107551,0.9935 -1.8257744996762515,1.0025 -1.8661352386286207,0.96075 -1.9045870237116205,0.92125 -1.9465840088377355,0.8855 -1.986944747790103,0.85725 -2.025669240568728,0.832 -2.065757271825472,0.80675 -2.1066634261690886,0.78875 -2.1464787497302105,0.7705 -2.1865667809869542,0.75625 -2.2261093968524506,0.74475 -2.2683790896741876,0.68275 -2.3090125363221823,0.6375 -2.3510095214482956,0.59925 -2.3916429680962885,0.5665 -2.4330945378311526,0.538 -2.4783640153047557,0.50825 -2.5203610004308707,0.4875 -2.562903400948233,0.46825 -2.599173524466238,0.45 -2.642806755766097,0.4355 -2.685076448587836,0.42275 -2.722437402888339,0.4125 -2.766888757275069,0.40125 -2.8007045115324587,0.39525 -2.841883373571701,0.385 -2.8819714048284446,0.3805 -2.922332143780814,0.38575 -2.9637837135156797,0.38425 -3.0005992524249336,0.36575 -3.0401418682904318,0.3765 -3.079957191851552,0.3915 -3.115409192282687,0.408 -3.154679100452558,0.4265 -3.184949654666836,0.447 -3.2242195628367085,0.4715 -3.2574899017028507,0.49875 -3.2959416867858504,0.52875 -3.3292120256519926,0.564 -3.3665729799524957,0.6055 -3.4031158111661277,0.6515 -3.438022396206014,0.70675 -3.4756560582021407,0.771 -3.513562427893893,0.77075 -3.5522869206725183,0.7785 -3.621827383056667,0.79575 -3.65918833735717,0.8045 -3.697367414744546,0.81725 -3.7377281536969154,0.83325 -3.775634523388667,0.8415 -3.8135408930804187,0.85575 -3.8522653858590425,0.87325 -3.8898990478551703,0.88725 -3.9299870791119154,0.906 -3.9665299103255465,0.9265 -4.006072526191043,0.94575 -4.043978895882795,0.97175 -4.081885265574547,1.02075 -4.1206097583531704,1.046 -4.1587888357405465,1.07025 -4.196422497736674,1.097 -4.234874282819675,1.12575 -4.286688744988257,0.73475 -4.324322406984384,0.72225 -4.364410438241129,0.731 -4.405862007975994,0.7405 -4.44267754688525,0.749 -4.484129116620115,0.76025 -4.522853609398739,0.76825 -4.560759979090491,0.77125 -4.5989390564778665,0.77725 -4.640117918517108,0.782 -4.679115118991357,0.78425 -4.717294196378733,0.789 -4.757109519939853,0.78825 -4.796652135805349,0.7855 -4.8337403824102285,0.786 -4.871646752101981,0.78275 -4.9109166602718535,0.7785 -4.950186568441726,0.7635 -4.990274599698471,0.74725 -5.028180969390222,0.737 -5.0677235852557185,0.72575 -5.109720570381833,0.71525 -5.149263186247329,0.70625 -5.1863514328522085,0.69975 -5.230530079543315,0.693 -5.269799987713188,0.68925 -5.307979065100563,0.68425 -5.347248973270435,0.68275 -5.386518881440308,0.68075 -5.426606912697053,0.68175 -5.465604113171301,0.67825 -5.502419652080556,0.6835 -5.543871221815422,0.6885 -5.580959468420302,0.67925 -5.624319992024535,0.6555 -5.660044700151294,0.639 -5.700950854494911,0.623 -5.740220762664784,0.6075 -5.783581286269018,0.59475 -5.820124117482649,0.58475 -5.861848394913139,0.57325 -5.899209349213642,0.565 -5.938751965079138,0.55525 -5.9782945809446355,0.55175 -6.017564489114507,0.546 -6.059288766544997,0.5405 -6.097467843932373,0.53825 -6.139464829058487,0.534 -6.176825783358991,0.5325 -6.215822983833238,0.53125 -6.252911230438118,0.53075 \ No newline at end of file diff --git a/Mapping/lidar_to_grid_map/lidar_to_grid_map.py b/Mapping/lidar_to_grid_map/lidar_to_grid_map.py deleted file mode 100644 index ad987392f5d..00000000000 --- a/Mapping/lidar_to_grid_map/lidar_to_grid_map.py +++ /dev/null @@ -1,240 +0,0 @@ -""" - -LIDAR to 2D grid map example - -author: Erno Horvath, Csaba Hajdu based on Atsushi Sakai's scripts - -""" - -import math -from collections import deque - -import matplotlib.pyplot as plt -import numpy as np - -EXTEND_AREA = 1.0 - - -def file_read(f): - """ - Reading LIDAR laser beams (angles and corresponding distance data) - """ - with open(f) as data: - measures = [line.split(",") for line in data] - angles = [] - distances = [] - for measure in measures: - angles.append(float(measure[0])) - distances.append(float(measure[1])) - angles = np.array(angles) - distances = np.array(distances) - return angles, distances - - -def bresenham(start, end): - """ - Implementation of Bresenham's line drawing algorithm - See en.wikipedia.org/wiki/Bresenham's_line_algorithm - Bresenham's Line Algorithm - Produces a np.array from start and end (original from roguebasin.com) - >>> points1 = bresenham((4, 4), (6, 10)) - >>> print(points1) - np.array([[4,4], [4,5], [5,6], [5,7], [5,8], [6,9], [6,10]]) - """ - # setup initial conditions - x1, y1 = start - x2, y2 = end - dx = x2 - x1 - dy = y2 - y1 - is_steep = abs(dy) > abs(dx) # determine how steep the line is - if is_steep: # rotate line - x1, y1 = y1, x1 - x2, y2 = y2, x2 - # swap start and end points if necessary and store swap state - swapped = False - if x1 > x2: - x1, x2 = x2, x1 - y1, y2 = y2, y1 - swapped = True - dx = x2 - x1 # recalculate differentials - dy = y2 - y1 # recalculate differentials - error = int(dx / 2.0) # calculate error - y_step = 1 if y1 < y2 else -1 - # iterate over bounding box generating points between start and end - y = y1 - points = [] - for x in range(x1, x2 + 1): - coord = [y, x] if is_steep else (x, y) - points.append(coord) - error -= abs(dy) - if error < 0: - y += y_step - error += dx - if swapped: # reverse the list if the coordinates were swapped - points.reverse() - points = np.array(points) - return points - - -def calc_grid_map_config(ox, oy, xy_resolution): - """ - Calculates the size, and the maximum distances according to the the - measurement center - """ - min_x = round(min(ox) - EXTEND_AREA / 2.0) - min_y = round(min(oy) - EXTEND_AREA / 2.0) - max_x = round(max(ox) + EXTEND_AREA / 2.0) - max_y = round(max(oy) + EXTEND_AREA / 2.0) - xw = int(round((max_x - min_x) / xy_resolution)) - yw = int(round((max_y - min_y) / xy_resolution)) - print("The grid map is ", xw, "x", yw, ".") - return min_x, min_y, max_x, max_y, xw, yw - - -def atan_zero_to_twopi(y, x): - angle = math.atan2(y, x) - if angle < 0.0: - angle += math.pi * 2.0 - return angle - - -def init_flood_fill(center_point, obstacle_points, xy_points, min_coord, - xy_resolution): - """ - center_point: center point - obstacle_points: detected obstacles points (x,y) - xy_points: (x,y) point pairs - """ - center_x, center_y = center_point - prev_ix, prev_iy = center_x - 1, center_y - ox, oy = obstacle_points - xw, yw = xy_points - min_x, min_y = min_coord - occupancy_map = (np.ones((xw, yw))) * 0.5 - for (x, y) in zip(ox, oy): - # x coordinate of the the occupied area - ix = int(round((x - min_x) / xy_resolution)) - # y coordinate of the the occupied area - iy = int(round((y - min_y) / xy_resolution)) - free_area = bresenham((prev_ix, prev_iy), (ix, iy)) - for fa in free_area: - occupancy_map[fa[0]][fa[1]] = 0 # free area 0.0 - prev_ix = ix - prev_iy = iy - return occupancy_map - - -def flood_fill(center_point, occupancy_map): - """ - center_point: starting point (x,y) of fill - occupancy_map: occupancy map generated from Bresenham ray-tracing - """ - # Fill empty areas with queue method - sx, sy = occupancy_map.shape - fringe = deque() - fringe.appendleft(center_point) - while fringe: - n = fringe.pop() - nx, ny = n - # West - if nx > 0: - if occupancy_map[nx - 1, ny] == 0.5: - occupancy_map[nx - 1, ny] = 0.0 - fringe.appendleft((nx - 1, ny)) - # East - if nx < sx - 1: - if occupancy_map[nx + 1, ny] == 0.5: - occupancy_map[nx + 1, ny] = 0.0 - fringe.appendleft((nx + 1, ny)) - # North - if ny > 0: - if occupancy_map[nx, ny - 1] == 0.5: - occupancy_map[nx, ny - 1] = 0.0 - fringe.appendleft((nx, ny - 1)) - # South - if ny < sy - 1: - if occupancy_map[nx, ny + 1] == 0.5: - occupancy_map[nx, ny + 1] = 0.0 - fringe.appendleft((nx, ny + 1)) - - -def generate_ray_casting_grid_map(ox, oy, xy_resolution, breshen=True): - """ - The breshen boolean tells if it's computed with bresenham ray casting - (True) or with flood fill (False) - """ - min_x, min_y, max_x, max_y, x_w, y_w = calc_grid_map_config( - ox, oy, xy_resolution) - # default 0.5 -- [[0.5 for i in range(y_w)] for i in range(x_w)] - occupancy_map = np.ones((x_w, y_w)) / 2 - center_x = int( - round(-min_x / xy_resolution)) # center x coordinate of the grid map - center_y = int( - round(-min_y / xy_resolution)) # center y coordinate of the grid map - # occupancy grid computed with bresenham ray casting - if breshen: - for (x, y) in zip(ox, oy): - # x coordinate of the the occupied area - ix = int(round((x - min_x) / xy_resolution)) - # y coordinate of the the occupied area - iy = int(round((y - min_y) / xy_resolution)) - laser_beams = bresenham((center_x, center_y), ( - ix, iy)) # line form the lidar to the occupied point - for laser_beam in laser_beams: - occupancy_map[laser_beam[0]][ - laser_beam[1]] = 0.0 # free area 0.0 - occupancy_map[ix][iy] = 1.0 # occupied area 1.0 - occupancy_map[ix + 1][iy] = 1.0 # extend the occupied area - occupancy_map[ix][iy + 1] = 1.0 # extend the occupied area - occupancy_map[ix + 1][iy + 1] = 1.0 # extend the occupied area - # occupancy grid computed with with flood fill - else: - occupancy_map = init_flood_fill((center_x, center_y), (ox, oy), - (x_w, y_w), - (min_x, min_y), xy_resolution) - flood_fill((center_x, center_y), occupancy_map) - occupancy_map = np.array(occupancy_map, dtype=float) - for (x, y) in zip(ox, oy): - ix = int(round((x - min_x) / xy_resolution)) - iy = int(round((y - min_y) / xy_resolution)) - occupancy_map[ix][iy] = 1.0 # occupied area 1.0 - occupancy_map[ix + 1][iy] = 1.0 # extend the occupied area - occupancy_map[ix][iy + 1] = 1.0 # extend the occupied area - occupancy_map[ix + 1][iy + 1] = 1.0 # extend the occupied area - return occupancy_map, min_x, max_x, min_y, max_y, xy_resolution - - -def main(): - """ - Example usage - """ - print(__file__, "start") - xy_resolution = 0.02 # x-y grid resolution - ang, dist = file_read("lidar01.csv") - ox = np.sin(ang) * dist - oy = np.cos(ang) * dist - occupancy_map, min_x, max_x, min_y, max_y, xy_resolution = \ - generate_ray_casting_grid_map(ox, oy, xy_resolution, True) - xy_res = np.array(occupancy_map).shape - plt.figure(1, figsize=(10, 4)) - plt.subplot(122) - plt.imshow(occupancy_map, cmap="PiYG_r") - # cmap = "binary" "PiYG_r" "PiYG_r" "bone" "bone_r" "RdYlGn_r" - plt.clim(-0.4, 1.4) - plt.gca().set_xticks(np.arange(-.5, xy_res[1], 1), minor=True) - plt.gca().set_yticks(np.arange(-.5, xy_res[0], 1), minor=True) - plt.grid(True, which="minor", color="w", linewidth=0.6, alpha=0.5) - plt.colorbar() - plt.subplot(121) - plt.plot([oy, np.zeros(np.size(oy))], [ox, np.zeros(np.size(oy))], "ro-") - plt.axis("equal") - plt.plot(0.0, 0.0, "ob") - plt.gca().set_aspect("equal", "box") - bottom, top = plt.ylim() # return the current y-lim - plt.ylim((top, bottom)) # rescale y axis, to match the grid orientation - plt.grid(True) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/Mapping/ndt_map/ndt_map.py b/Mapping/ndt_map/ndt_map.py deleted file mode 100644 index f4f32996625..00000000000 --- a/Mapping/ndt_map/ndt_map.py +++ /dev/null @@ -1,135 +0,0 @@ -""" -Normal Distribution Transform (NDTGrid) mapping sample -""" -import matplotlib.pyplot as plt -import numpy as np -from collections import defaultdict - -from Mapping.grid_map_lib.grid_map_lib import GridMap -from utils.plot import plot_covariance_ellipse - - -class NDTMap: - """ - Normal Distribution Transform (NDT) map class - - :param ox: obstacle x position list - :param oy: obstacle y position list - :param resolution: grid resolution [m] - """ - - class NDTGrid: - """ - NDT grid - """ - - def __init__(self): - #: Number of points in the NDTGrid grid - self.n_points = 0 - #: Mean x position of points in the NDTGrid cell - self.mean_x = None - #: Mean y position of points in the NDTGrid cell - self.mean_y = None - #: Center x position of the NDT grid - self.center_grid_x = None - #: Center y position of the NDT grid - self.center_grid_y = None - #: Covariance matrix of the NDT grid - self.covariance = None - #: Eigen vectors of the NDT grid - self.eig_vec = None - #: Eigen values of the NDT grid - self.eig_values = None - - def __init__(self, ox, oy, resolution): - #: Minimum number of points in the NDT grid - self.min_n_points = 3 - #: Resolution of the NDT grid [m] - self.resolution = resolution - width = int((max(ox) - min(ox))/resolution) + 3 # rounding up + right and left margin - height = int((max(oy) - min(oy))/resolution) + 3 - center_x = np.mean(ox) - center_y = np.mean(oy) - self.ox = ox - self.oy = oy - #: NDT grid index map - self.grid_index_map = self._create_grid_index_map(ox, oy) - - #: NDT grid map. Each grid contains NDTGrid object - self._construct_grid_map(center_x, center_y, height, ox, oy, resolution, width) - - def _construct_grid_map(self, center_x, center_y, height, ox, oy, resolution, width): - self.grid_map = GridMap(width, height, resolution, center_x, center_y, self.NDTGrid()) - for grid_index, inds in self.grid_index_map.items(): - ndt = self.NDTGrid() - ndt.n_points = len(inds) - if ndt.n_points >= self.min_n_points: - ndt.mean_x = np.mean(ox[inds]) - ndt.mean_y = np.mean(oy[inds]) - ndt.center_grid_x, ndt.center_grid_y = \ - self.grid_map.calc_grid_central_xy_position_from_grid_index(grid_index) - ndt.covariance = np.cov(ox[inds], oy[inds]) - ndt.eig_values, ndt.eig_vec = np.linalg.eig(ndt.covariance) - self.grid_map.data[grid_index] = ndt - - def _create_grid_index_map(self, ox, oy): - grid_index_map = defaultdict(list) - for i in range(len(ox)): - grid_index = self.grid_map.calc_grid_index_from_xy_pos(ox[i], oy[i]) - grid_index_map[grid_index].append(i) - return grid_index_map - - -def create_dummy_observation_data(): - ox = [] - oy = [] - # left corridor - for y in range(-50, 50): - ox.append(-20.0) - oy.append(y) - # right corridor 1 - for y in range(-50, 0): - ox.append(20.0) - oy.append(y) - # right corridor 2 - for x in range(20, 50): - ox.append(x) - oy.append(0) - # right corridor 3 - for x in range(20, 50): - ox.append(x) - oy.append(x/2.0+10) - # right corridor 4 - for y in range(20, 50): - ox.append(20) - oy.append(y) - ox = np.array(ox) - oy = np.array(oy) - # Adding random noize - ox += np.random.rand(len(ox)) * 1.0 - oy += np.random.rand(len(ox)) * 1.0 - return ox, oy - - -def main(): - print(__file__ + " start!!") - - ox, oy = create_dummy_observation_data() - grid_resolution = 10.0 - ndt_map = NDTMap(ox, oy, grid_resolution) - - # plot raw observation - plt.plot(ox, oy, ".r") - - # plot grid clustering - [plt.plot(ox[inds], oy[inds], "x") for inds in ndt_map.grid_index_map.values()] - - # plot ndt grid map - [plot_covariance_ellipse(ndt.mean_x, ndt.mean_y, ndt.covariance, color="-k") for ndt in ndt_map.grid_map.data if ndt.n_points > 0] - - plt.axis("equal") - plt.show() - - -if __name__ == '__main__': - main() diff --git a/Mapping/normal_vector_estimation/normal_vector_estimation.py b/Mapping/normal_vector_estimation/normal_vector_estimation.py deleted file mode 100644 index 996ba3ffee5..00000000000 --- a/Mapping/normal_vector_estimation/normal_vector_estimation.py +++ /dev/null @@ -1,177 +0,0 @@ -import numpy as np -from matplotlib import pyplot as plt - -from utils.plot import plot_3d_vector_arrow, plot_triangle, set_equal_3d_axis - -show_animation = True - - -def calc_normal_vector(p1, p2, p3): - """Calculate normal vector of triangle - - Parameters - ---------- - p1 : np.array - 3D point - p2 : np.array - 3D point - p3 : np.array - 3D point - - Returns - ------- - normal_vector : np.array - normal vector (3,) - - """ - # calculate two vectors of triangle - v1 = p2 - p1 - v2 = p3 - p1 - - # calculate normal vector - normal_vector = np.cross(v1, v2) - - # normalize vector - normal_vector = normal_vector / np.linalg.norm(normal_vector) - - return normal_vector - - -def sample_3d_points_from_a_plane(num_samples, normal): - points_2d = np.random.normal(size=(num_samples, 2)) # 2D points on a plane - d = 0 - for i in range(len(points_2d)): - point_3d = np.append(points_2d[i], 0) - d += normal @ point_3d - d /= len(points_2d) - - points_3d = np.zeros((len(points_2d), 3)) - for i in range(len(points_2d)): - point_2d = np.append(points_2d[i], 0) - projection_length = (d - normal @ point_2d) / np.linalg.norm(normal) - points_3d[i] = point_2d + projection_length * normal - - return points_3d - - -def distance_to_plane(point, normal, origin): - dot_product = np.dot(normal, point) - np.dot(normal, origin) - if np.isclose(dot_product, 0): - return 0.0 - else: - distance = abs(dot_product) / np.linalg.norm(normal) - return distance - - -def ransac_normal_vector_estimation(points_3d, inlier_radio_th=0.7, - inlier_dist=0.1, p=0.99): - """ - RANSAC based normal vector estimation - - Parameters - ---------- - points_3d : np.array - 3D points (N, 3) - inlier_radio_th : float - Inlier ratio threshold. If inlier ratio is larger than this value, - the iteration is stopped. Default is 0.7. - inlier_dist : float - Inlier distance threshold. If distance between points and estimated - plane is smaller than this value, the point is inlier. Default is 0.1. - p : float - Probability that at least one of the sets of random samples does not - include an outlier. If this probability is near 1, the iteration - number is large. Default is 0.99. - - Returns - ------- - center_vector : np.array - Center of estimated plane. (3,) - normal_vector : np.array - Normal vector of estimated plane. (3,) - - """ - center = np.mean(points_3d, axis=0) - - max_iter = int(np.floor(np.log(1.0-p)/np.log(1.0-(1.0-inlier_radio_th)**3))) - - for ite in range(max_iter): - # Random sampling - sampled_ids = np.random.choice(points_3d.shape[0], size=3, - replace=False) - sampled_points = points_3d[sampled_ids, :] - p1 = sampled_points[0, :] - p2 = sampled_points[1, :] - p3 = sampled_points[2, :] - normal_vector = calc_normal_vector(p1, p2, p3) - - # calc inlier ratio - n_inliner = 0 - for i in range(points_3d.shape[0]): - p = points_3d[i, :] - if distance_to_plane(p, normal_vector, center) <= inlier_dist: - n_inliner += 1 - inlier_ratio = n_inliner / points_3d.shape[0] - print(f"Iter:{ite}, {inlier_ratio=}") - if inlier_ratio > inlier_radio_th: - return center, normal_vector - - return center, None - - -def main1(): - p1 = np.array([0.0, 0.0, 1.0]) - p2 = np.array([1.0, 1.0, 0.0]) - p3 = np.array([0.0, 1.0, 0.0]) - - center = np.mean([p1, p2, p3], axis=0) - normal_vector = calc_normal_vector(p1, p2, p3) - print(f"{center=}") - print(f"{normal_vector=}") - - if show_animation: - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - set_equal_3d_axis(ax, [0.0, 2.5], [0.0, 2.5], [0.0, 3.0]) - plot_triangle(p1, p2, p3, ax) - ax.plot(center[0], center[1], center[2], "ro") - plot_3d_vector_arrow(ax, center, center + normal_vector) - plt.show() - - -def main2(rng=None): - true_normal = np.array([0, 1, 1]) - true_normal = true_normal / np.linalg.norm(true_normal) - num_samples = 100 - noise_scale = 0.1 - - points_3d = sample_3d_points_from_a_plane(num_samples, true_normal) - # add random noise - points_3d += np.random.normal(size=points_3d.shape, scale=noise_scale) - - print(f"{points_3d.shape=}") - - center, estimated_normal = ransac_normal_vector_estimation( - points_3d, inlier_dist=noise_scale) - - if estimated_normal is None: - print("Failed to estimate normal vector") - return - - print(f"{true_normal=}") - print(f"{estimated_normal=}") - - if show_animation: - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - ax.plot(points_3d[:, 0], points_3d[:, 1], points_3d[:, 2], ".r") - plot_3d_vector_arrow(ax, center, center + true_normal) - plot_3d_vector_arrow(ax, center, center + estimated_normal) - set_equal_3d_axis(ax, [-3.0, 3.0], [-3.0, 3.0], [-3.0, 3.0]) - plt.title("RANSAC based Normal vector estimation") - plt.show() - - -if __name__ == '__main__': - # main1() - main2() diff --git a/Mapping/point_cloud_sampling/point_cloud_sampling.py b/Mapping/point_cloud_sampling/point_cloud_sampling.py deleted file mode 100644 index df7cde41c06..00000000000 --- a/Mapping/point_cloud_sampling/point_cloud_sampling.py +++ /dev/null @@ -1,168 +0,0 @@ -""" -Point cloud sampling example codes. This code supports -- Voxel point sampling -- Farthest point sampling -- Poisson disk sampling - -""" -import matplotlib.pyplot as plt -import numpy as np -import numpy.typing as npt -from collections import defaultdict - -do_plot = True - - -def voxel_point_sampling(original_points: npt.NDArray, voxel_size: float): - """ - Voxel Point Sampling function. - This function sample N-dimensional points with voxel grid. - Points in a same voxel grid will be merged by mean operation for sampling. - - Parameters - ---------- - original_points : (M, N) N-dimensional points for sampling. - The number of points is M. - voxel_size : voxel grid size - - Returns - ------- - sampled points (M', N) - """ - voxel_dict = defaultdict(list) - for i in range(original_points.shape[0]): - xyz = original_points[i, :] - xyz_index = tuple(xyz // voxel_size) - voxel_dict[xyz_index].append(xyz) - points = np.vstack([np.mean(v, axis=0) for v in voxel_dict.values()]) - return points - - -def farthest_point_sampling(orig_points: npt.NDArray, - n_points: int, seed: int): - """ - Farthest point sampling function - This function sample N-dimensional points with the farthest point policy. - - Parameters - ---------- - orig_points : (M, N) N-dimensional points for sampling. - The number of points is M. - n_points : number of points for sampling - seed : random seed number - - Returns - ------- - sampled points (n_points, N) - - """ - rng = np.random.default_rng(seed) - n_orig_points = orig_points.shape[0] - first_point_id = rng.choice(range(n_orig_points)) - min_distances = np.ones(n_orig_points) * float("inf") - selected_ids = [first_point_id] - while len(selected_ids) < n_points: - base_point = orig_points[selected_ids[-1], :] - distances = np.linalg.norm(orig_points[np.newaxis, :] - base_point, - axis=2).flatten() - min_distances = np.minimum(min_distances, distances) - distances_rank = np.argsort(-min_distances) # Farthest order - for i in distances_rank: # From the farthest point - if i not in selected_ids: # if not selected yes, select it - selected_ids.append(i) - break - return orig_points[selected_ids, :] - - -def poisson_disk_sampling(orig_points: npt.NDArray, n_points: int, - min_distance: float, seed: int, MAX_ITER=1000): - """ - Poisson disk sampling function - This function sample N-dimensional points randomly until the number of - points keeping minimum distance between selected points. - - Parameters - ---------- - orig_points : (M, N) N-dimensional points for sampling. - The number of points is M. - n_points : number of points for sampling - min_distance : minimum distance between selected points. - seed : random seed number - MAX_ITER : Maximum number of iteration. Default is 1000. - - Returns - ------- - sampled points (n_points or less, N) - """ - rng = np.random.default_rng(seed) - selected_id = rng.choice(range(orig_points.shape[0])) - selected_ids = [selected_id] - loop = 0 - while len(selected_ids) < n_points and loop <= MAX_ITER: - selected_id = rng.choice(range(orig_points.shape[0])) - base_point = orig_points[selected_id, :] - distances = np.linalg.norm( - orig_points[np.newaxis, selected_ids] - base_point, - axis=2).flatten() - if min(distances) >= min_distance: - selected_ids.append(selected_id) - loop += 1 - if len(selected_ids) != n_points: - print("Could not find the specified number of points...") - - return orig_points[selected_ids, :] - - -def plot_sampled_points(original_points, sampled_points, method_name): - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - ax.scatter(original_points[:, 0], original_points[:, 1], - original_points[:, 2], marker=".", label="Original points") - ax.scatter(sampled_points[:, 0], sampled_points[:, 1], - sampled_points[:, 2], marker="o", - label="Filtered points") - plt.legend() - plt.title(method_name) - plt.axis("equal") - - -def main(): - n_points = 1000 - seed = 1234 - rng = np.random.default_rng(seed) - - x = rng.normal(0.0, 10.0, n_points) - y = rng.normal(0.0, 1.0, n_points) - z = rng.normal(0.0, 10.0, n_points) - original_points = np.vstack((x, y, z)).T - print(f"{original_points.shape=}") - print("Voxel point sampling") - voxel_size = 20.0 - voxel_sampling_points = voxel_point_sampling(original_points, voxel_size) - print(f"{voxel_sampling_points.shape=}") - - print("Farthest point sampling") - n_points = 20 - farthest_sampling_points = farthest_point_sampling(original_points, - n_points, seed) - print(f"{farthest_sampling_points.shape=}") - - print("Poisson disk sampling") - n_points = 20 - min_distance = 10.0 - poisson_disk_points = poisson_disk_sampling(original_points, n_points, - min_distance, seed) - print(f"{poisson_disk_points.shape=}") - - if do_plot: - plot_sampled_points(original_points, voxel_sampling_points, - "Voxel point sampling") - plot_sampled_points(original_points, farthest_sampling_points, - "Farthest point sampling") - plot_sampled_points(original_points, poisson_disk_points, - "poisson disk sampling") - plt.show() - - -if __name__ == '__main__': - main() diff --git a/Mapping/raycasting_grid_map/raycasting_grid_map.py b/Mapping/raycasting_grid_map/raycasting_grid_map.py deleted file mode 100644 index 8ce37b925b0..00000000000 --- a/Mapping/raycasting_grid_map/raycasting_grid_map.py +++ /dev/null @@ -1,137 +0,0 @@ -""" - -Ray casting 2D grid map example - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math -import numpy as np -import matplotlib.pyplot as plt - -EXTEND_AREA = 10.0 - -show_animation = True - - -def calc_grid_map_config(ox, oy, xyreso): - minx = round(min(ox) - EXTEND_AREA / 2.0) - miny = round(min(oy) - EXTEND_AREA / 2.0) - maxx = round(max(ox) + EXTEND_AREA / 2.0) - maxy = round(max(oy) + EXTEND_AREA / 2.0) - xw = int(round((maxx - minx) / xyreso)) - yw = int(round((maxy - miny) / xyreso)) - - return minx, miny, maxx, maxy, xw, yw - - -class precastDB: - - def __init__(self): - self.px = 0.0 - self.py = 0.0 - self.d = 0.0 - self.angle = 0.0 - self.ix = 0 - self.iy = 0 - - def __str__(self): - return str(self.px) + "," + str(self.py) + "," + str(self.d) + "," + str(self.angle) - - -def atan_zero_to_twopi(y, x): - angle = math.atan2(y, x) - if angle < 0.0: - angle += math.pi * 2.0 - - return angle - - -def precasting(minx, miny, xw, yw, xyreso, yawreso): - - precast = [[] for i in range(int(round((math.pi * 2.0) / yawreso)) + 1)] - - for ix in range(xw): - for iy in range(yw): - px = ix * xyreso + minx - py = iy * xyreso + miny - - d = math.hypot(px, py) - angle = atan_zero_to_twopi(py, px) - angleid = int(math.floor(angle / yawreso)) - - pc = precastDB() - - pc.px = px - pc.py = py - pc.d = d - pc.ix = ix - pc.iy = iy - pc.angle = angle - - precast[angleid].append(pc) - - return precast - - -def generate_ray_casting_grid_map(ox, oy, xyreso, yawreso): - - minx, miny, maxx, maxy, xw, yw = calc_grid_map_config(ox, oy, xyreso) - - pmap = [[0.0 for i in range(yw)] for i in range(xw)] - - precast = precasting(minx, miny, xw, yw, xyreso, yawreso) - - for (x, y) in zip(ox, oy): - - d = math.hypot(x, y) - angle = atan_zero_to_twopi(y, x) - angleid = int(math.floor(angle / yawreso)) - - gridlist = precast[angleid] - - ix = int(round((x - minx) / xyreso)) - iy = int(round((y - miny) / xyreso)) - - for grid in gridlist: - if grid.d > d: - pmap[grid.ix][grid.iy] = 0.5 - - pmap[ix][iy] = 1.0 - - return pmap, minx, maxx, miny, maxy, xyreso - - -def draw_heatmap(data, minx, maxx, miny, maxy, xyreso): - x, y = np.mgrid[slice(minx - xyreso / 2.0, maxx + xyreso / 2.0, xyreso), - slice(miny - xyreso / 2.0, maxy + xyreso / 2.0, xyreso)] - plt.pcolor(x, y, data, vmax=1.0, cmap=plt.cm.Blues) - plt.axis("equal") - - -def main(): - print(__file__ + " start!!") - - xyreso = 0.25 # x-y grid resolution [m] - yawreso = np.deg2rad(10.0) # yaw angle resolution [rad] - - for i in range(5): - ox = (np.random.rand(4) - 0.5) * 10.0 - oy = (np.random.rand(4) - 0.5) * 10.0 - pmap, minx, maxx, miny, maxy, xyreso = generate_ray_casting_grid_map( - ox, oy, xyreso, yawreso) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - draw_heatmap(pmap, minx, maxx, miny, maxy, xyreso) - plt.plot(ox, oy, "xr") - plt.plot(0.0, 0.0, "ob") - plt.pause(1.0) - - -if __name__ == '__main__': - main() diff --git a/Mapping/rectangle_fitting/__init_.py b/Mapping/rectangle_fitting/__init_.py deleted file mode 100644 index 2194d4c3033..00000000000 --- a/Mapping/rectangle_fitting/__init_.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent)) diff --git a/Mapping/rectangle_fitting/rectangle_fitting.py b/Mapping/rectangle_fitting/rectangle_fitting.py deleted file mode 100644 index 177f0788718..00000000000 --- a/Mapping/rectangle_fitting/rectangle_fitting.py +++ /dev/null @@ -1,291 +0,0 @@ -""" - -Object shape recognition with L-shape fitting - -author: Atsushi Sakai (@Atsushi_twi) - -Ref: -- Efficient L-Shape Fitting for Vehicle Detection Using Laser Scanners - -The Robotics Institute Carnegie Mellon University -https://www.ri.cmu.edu/publications/ -efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners/ - -""" - -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import matplotlib.pyplot as plt -import numpy as np -import itertools -from enum import Enum - -from utils.angle import rot_mat_2d - -from Mapping.rectangle_fitting.simulator \ - import VehicleSimulator, LidarSimulator - -show_animation = True - - -class LShapeFitting: - """ - LShapeFitting class. You can use this class by initializing the class and - changing the parameters, and then calling the fitting method. - - """ - - class Criteria(Enum): - AREA = 1 - CLOSENESS = 2 - VARIANCE = 3 - - def __init__(self): - """ - Default parameter settings - """ - #: Fitting criteria parameter - self.criteria = self.Criteria.VARIANCE - #: Minimum distance for closeness criteria parameter [m] - self.min_dist_of_closeness_criteria = 0.01 - #: Angle difference parameter [deg] - self.d_theta_deg_for_search = 1.0 - #: Range segmentation parameter [m] - self.R0 = 3.0 - #: Range segmentation parameter [m] - self.Rd = 0.001 - - def fitting(self, ox, oy): - """ - Fitting L-shape model to object points - - Parameters - ---------- - ox : x positions of range points from an object - oy : y positions of range points from an object - - Returns - ------- - rects: Fitting rectangles - id_sets: id sets of each cluster - - """ - # step1: Adaptive Range Segmentation - id_sets = self._adoptive_range_segmentation(ox, oy) - - # step2 Rectangle search - rects = [] - for ids in id_sets: # for each cluster - cx = [ox[i] for i in range(len(ox)) if i in ids] - cy = [oy[i] for i in range(len(oy)) if i in ids] - rects.append(self._rectangle_search(cx, cy)) - - return rects, id_sets - - @staticmethod - def _calc_area_criterion(c1, c2): - c1_max, c1_min, c2_max, c2_min = LShapeFitting._find_min_max(c1, c2) - alpha = -(c1_max - c1_min) * (c2_max - c2_min) - return alpha - - def _calc_closeness_criterion(self, c1, c2): - c1_max, c1_min, c2_max, c2_min = LShapeFitting._find_min_max(c1, c2) - - # Vectorization - d1 = np.minimum(c1_max - c1, c1 - c1_min) - d2 = np.minimum(c2_max - c2, c2 - c2_min) - d = np.maximum(np.minimum(d1, d2), self.min_dist_of_closeness_criteria) - beta = (1.0 / d).sum() - - return beta - - @staticmethod - def _calc_variance_criterion(c1, c2): - c1_max, c1_min, c2_max, c2_min = LShapeFitting._find_min_max(c1, c2) - - # Vectorization - d1 = np.minimum(c1_max - c1, c1 - c1_min) - d2 = np.minimum(c2_max - c2, c2 - c2_min) - e1 = d1[d1 < d2] - e2 = d2[d1 >= d2] - v1 = - np.var(e1) if len(e1) > 0 else 0. - v2 = - np.var(e2) if len(e2) > 0 else 0. - gamma = v1 + v2 - - return gamma - - @staticmethod - def _find_min_max(c1, c2): - c1_max = max(c1) - c2_max = max(c2) - c1_min = min(c1) - c2_min = min(c2) - return c1_max, c1_min, c2_max, c2_min - - def _rectangle_search(self, x, y): - - xy = np.array([x, y]).T - - d_theta = np.deg2rad(self.d_theta_deg_for_search) - min_cost = (-float('inf'), None) - for theta in np.arange(0.0, np.pi / 2.0 - d_theta, d_theta): - - c = xy @ rot_mat_2d(theta) - c1 = c[:, 0] - c2 = c[:, 1] - - # Select criteria - cost = 0.0 - if self.criteria == self.Criteria.AREA: - cost = self._calc_area_criterion(c1, c2) - elif self.criteria == self.Criteria.CLOSENESS: - cost = self._calc_closeness_criterion(c1, c2) - elif self.criteria == self.Criteria.VARIANCE: - cost = self._calc_variance_criterion(c1, c2) - - if min_cost[0] < cost: - min_cost = (cost, theta) - - # calc best rectangle - sin_s = np.sin(min_cost[1]) - cos_s = np.cos(min_cost[1]) - - c1_s = xy @ np.array([cos_s, sin_s]).T - c2_s = xy @ np.array([-sin_s, cos_s]).T - - rect = RectangleData() - rect.a[0] = cos_s - rect.b[0] = sin_s - rect.c[0] = min(c1_s) - rect.a[1] = -sin_s - rect.b[1] = cos_s - rect.c[1] = min(c2_s) - rect.a[2] = cos_s - rect.b[2] = sin_s - rect.c[2] = max(c1_s) - rect.a[3] = -sin_s - rect.b[3] = cos_s - rect.c[3] = max(c2_s) - - return rect - - def _adoptive_range_segmentation(self, ox, oy): - - # Setup initial cluster - segment_list = [] - for i, _ in enumerate(ox): - c = set() - r = self.R0 + self.Rd * np.linalg.norm([ox[i], oy[i]]) - for j, _ in enumerate(ox): - d = np.hypot(ox[i] - ox[j], oy[i] - oy[j]) - if d <= r: - c.add(j) - segment_list.append(c) - - # Merge cluster - while True: - no_change = True - for (c1, c2) in list(itertools.permutations(range(len(segment_list)), 2)): - if segment_list[c1] & segment_list[c2]: - segment_list[c1] = (segment_list[c1] | segment_list.pop(c2)) - no_change = False - break - if no_change: - break - - return segment_list - - -class RectangleData: - - def __init__(self): - self.a = [None] * 4 - self.b = [None] * 4 - self.c = [None] * 4 - - self.rect_c_x = [None] * 5 - self.rect_c_y = [None] * 5 - - def plot(self): - self.calc_rect_contour() - plt.plot(self.rect_c_x, self.rect_c_y, "-r") - - def calc_rect_contour(self): - - self.rect_c_x[0], self.rect_c_y[0] = self.calc_cross_point( - self.a[0:2], self.b[0:2], self.c[0:2]) - self.rect_c_x[1], self.rect_c_y[1] = self.calc_cross_point( - self.a[1:3], self.b[1:3], self.c[1:3]) - self.rect_c_x[2], self.rect_c_y[2] = self.calc_cross_point( - self.a[2:4], self.b[2:4], self.c[2:4]) - self.rect_c_x[3], self.rect_c_y[3] = self.calc_cross_point( - [self.a[3], self.a[0]], [self.b[3], self.b[0]], [self.c[3], self.c[0]]) - self.rect_c_x[4], self.rect_c_y[4] = self.rect_c_x[0], self.rect_c_y[0] - - @staticmethod - def calc_cross_point(a, b, c): - x = (b[0] * -c[1] - b[1] * -c[0]) / (a[0] * b[1] - a[1] * b[0]) - y = (a[1] * -c[0] - a[0] * -c[1]) / (a[0] * b[1] - a[1] * b[0]) - return x, y - - -def main(): - - # simulation parameters - sim_time = 30.0 # simulation time - dt = 0.2 # time tick - - angle_resolution = np.deg2rad(3.0) # sensor angle resolution - - v1 = VehicleSimulator(-10.0, 0.0, np.deg2rad(90.0), - 0.0, 50.0 / 3.6, 3.0, 5.0) - v2 = VehicleSimulator(20.0, 10.0, np.deg2rad(180.0), - 0.0, 50.0 / 3.6, 4.0, 10.0) - - l_shape_fitting = LShapeFitting() - lidar_sim = LidarSimulator() - - time = 0.0 - while time <= sim_time: - time += dt - - v1.update(dt, 0.1, 0.0) - v2.update(dt, 0.1, -0.05) - - ox, oy = lidar_sim.get_observation_points([v1, v2], angle_resolution) - - rects, id_sets = l_shape_fitting.fitting(ox, oy) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.axis("equal") - plt.plot(0.0, 0.0, "*r") - v1.plot() - v2.plot() - - # Plot range observation - for ids in id_sets: - x = [ox[i] for i in range(len(ox)) if i in ids] - y = [oy[i] for i in range(len(ox)) if i in ids] - - for (ix, iy) in zip(x, y): - plt.plot([0.0, ix], [0.0, iy], "-og") - - plt.plot([ox[i] for i in range(len(ox)) if i in ids], - [oy[i] for i in range(len(ox)) if i in ids], - "o") - for rect in rects: - rect.plot() - - plt.pause(0.1) - - print("Done") - - -if __name__ == '__main__': - main() diff --git a/Mapping/rectangle_fitting/simulator.py b/Mapping/rectangle_fitting/simulator.py deleted file mode 100644 index aa32ae1b1fc..00000000000 --- a/Mapping/rectangle_fitting/simulator.py +++ /dev/null @@ -1,140 +0,0 @@ -""" - -Simulator - -author: Atsushi Sakai - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import numpy as np -import matplotlib.pyplot as plt -import math -import random - -from utils.angle import rot_mat_2d - - -class VehicleSimulator: - - def __init__(self, i_x, i_y, i_yaw, i_v, max_v, w, L): - self.x = i_x - self.y = i_y - self.yaw = i_yaw - self.v = i_v - self.max_v = max_v - self.W = w - self.L = L - self._calc_vehicle_contour() - - def update(self, dt, a, omega): - self.x += self.v * np.cos(self.yaw) * dt - self.y += self.v * np.sin(self.yaw) * dt - self.yaw += omega * dt - self.v += a * dt - if self.v >= self.max_v: - self.v = self.max_v - - def plot(self): - plt.plot(self.x, self.y, ".b") - - # convert global coordinate - gx, gy = self.calc_global_contour() - plt.plot(gx, gy, "--b") - - def calc_global_contour(self): - gxy = np.stack([self.vc_x, self.vc_y]).T @ rot_mat_2d(self.yaw) - gx = gxy[:, 0] + self.x - gy = gxy[:, 1] + self.y - - return gx, gy - - def _calc_vehicle_contour(self): - - self.vc_x = [] - self.vc_y = [] - - self.vc_x.append(self.L / 2.0) - self.vc_y.append(self.W / 2.0) - - self.vc_x.append(self.L / 2.0) - self.vc_y.append(-self.W / 2.0) - - self.vc_x.append(-self.L / 2.0) - self.vc_y.append(-self.W / 2.0) - - self.vc_x.append(-self.L / 2.0) - self.vc_y.append(self.W / 2.0) - - self.vc_x.append(self.L / 2.0) - self.vc_y.append(self.W / 2.0) - - self.vc_x, self.vc_y = self._interpolate(self.vc_x, self.vc_y) - - @staticmethod - def _interpolate(x, y): - rx, ry = [], [] - d_theta = 0.05 - for i in range(len(x) - 1): - rx.extend([(1.0 - theta) * x[i] + theta * x[i + 1] - for theta in np.arange(0.0, 1.0, d_theta)]) - ry.extend([(1.0 - theta) * y[i] + theta * y[i + 1] - for theta in np.arange(0.0, 1.0, d_theta)]) - - rx.extend([(1.0 - theta) * x[len(x) - 1] + theta * x[1] - for theta in np.arange(0.0, 1.0, d_theta)]) - ry.extend([(1.0 - theta) * y[len(y) - 1] + theta * y[1] - for theta in np.arange(0.0, 1.0, d_theta)]) - - return rx, ry - - -class LidarSimulator: - - def __init__(self): - self.range_noise = 0.01 - - def get_observation_points(self, v_list, angle_resolution): - x, y, angle, r = [], [], [], [] - - # store all points - for v in v_list: - - gx, gy = v.calc_global_contour() - - for vx, vy in zip(gx, gy): - v_angle = math.atan2(vy, vx) - vr = np.hypot(vx, vy) * random.uniform(1.0 - self.range_noise, - 1.0 + self.range_noise) - - x.append(vx) - y.append(vy) - angle.append(v_angle) - r.append(vr) - - # ray casting filter - rx, ry = self.ray_casting_filter(angle, r, angle_resolution) - - return rx, ry - - @staticmethod - def ray_casting_filter(theta_l, range_l, angle_resolution): - rx, ry = [], [] - range_db = [float("inf") for _ in range( - int(np.floor((np.pi * 2.0) / angle_resolution)) + 1)] - - for i in range(len(theta_l)): - angle_id = int(round(theta_l[i] / angle_resolution)) - - if range_db[angle_id] > range_l[i]: - range_db[angle_id] = range_l[i] - - for i in range(len(range_db)): - t = i * angle_resolution - if range_db[i] != float("inf"): - rx.append(range_db[i] * np.cos(t)) - ry.append(range_db[i] * np.sin(t)) - - return rx, ry diff --git a/MissionPlanning/BehaviorTree/behavior_tree.py b/MissionPlanning/BehaviorTree/behavior_tree.py deleted file mode 100644 index 59f4c713f1b..00000000000 --- a/MissionPlanning/BehaviorTree/behavior_tree.py +++ /dev/null @@ -1,690 +0,0 @@ -""" -Behavior Tree - -author: Wang Zheng (@Aglargil) - -Ref: - -- [Behavior Tree](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)) -""" - -import time -import xml.etree.ElementTree as ET -from enum import Enum - - -class Status(Enum): - SUCCESS = "success" - FAILURE = "failure" - RUNNING = "running" - - -class NodeType(Enum): - CONTROL_NODE = "ControlNode" - ACTION_NODE = "ActionNode" - DECORATOR_NODE = "DecoratorNode" - - -class Node: - """ - Base class for all nodes in a behavior tree. - """ - - def __init__(self, name): - self.name = name - self.status = None - - def tick(self) -> Status: - """ - Tick the node. - - Returns: - Status: The status of the node. - """ - raise ValueError("Node is not implemented") - - def tick_and_set_status(self) -> Status: - """ - Tick the node and set the status. - - Returns: - Status: The status of the node. - """ - self.status = self.tick() - return self.status - - def reset(self): - """ - Reset the node. - """ - self.status = None - - def reset_children(self): - """ - Reset the children of the node. - """ - pass - - -class ControlNode(Node): - """ - Base class for all control nodes in a behavior tree. - - Control nodes manage the execution flow of their child nodes according to specific rules. - They typically have multiple children and determine which children to execute and in what order. - """ - - def __init__(self, name): - super().__init__(name) - self.children = [] - self.type = NodeType.CONTROL_NODE - - def not_set_children_raise_error(self): - if len(self.children) == 0: - raise ValueError("Children are not set") - - def reset_children(self): - for child in self.children: - child.reset() - - -class SequenceNode(ControlNode): - """ - Executes child nodes in sequence until one fails or all succeed. - - Returns: - - Returns FAILURE if any child returns FAILURE - - Returns SUCCESS when all children have succeeded - - Returns RUNNING when a child is still running or when moving to the next child - - Example: - .. code-block:: xml - - <Sequence> - <Action1 /> - <Action2 /> - </Sequence> - """ - - def __init__(self, name): - super().__init__(name) - self.current_child_index = 0 - - def tick(self) -> Status: - self.not_set_children_raise_error() - - if self.current_child_index >= len(self.children): - self.reset_children() - return Status.SUCCESS - status = self.children[self.current_child_index].tick_and_set_status() - if status == Status.FAILURE: - self.reset_children() - return Status.FAILURE - elif status == Status.SUCCESS: - self.current_child_index += 1 - return Status.RUNNING - elif status == Status.RUNNING: - return Status.RUNNING - else: - raise ValueError("Unknown status") - - -class SelectorNode(ControlNode): - """ - Executes child nodes in sequence until one succeeds or all fail. - - Returns: - - Returns SUCCESS if any child returns SUCCESS - - Returns FAILURE when all children have failed - - Returns RUNNING when a child is still running or when moving to the next child - - Examples: - .. code-block:: xml - - <Selector> - <Action1 /> - <Action2 /> - </Selector> - """ - - def __init__(self, name): - super().__init__(name) - self.current_child_index = 0 - - def tick(self) -> Status: - self.not_set_children_raise_error() - - if self.current_child_index >= len(self.children): - self.reset_children() - return Status.FAILURE - status = self.children[self.current_child_index].tick_and_set_status() - if status == Status.SUCCESS: - self.reset_children() - return Status.SUCCESS - elif status == Status.FAILURE: - self.current_child_index += 1 - return Status.RUNNING - elif status == Status.RUNNING: - return Status.RUNNING - else: - raise ValueError("Unknown status") - - -class WhileDoElseNode(ControlNode): - """ - Conditional execution node with three parts: condition, do, and optional else. - - Returns: - First executes the condition node (child[0]) - If condition succeeds, executes do node (child[1]) and returns RUNNING - If condition fails, executes else node (child[2]) if present and returns result of else node - If condition fails and there is no else node, returns SUCCESS - - Example: - .. code-block:: xml - - <WhileDoElse> - <Condition /> - <Do /> - <Else /> - </WhileDoElse> - """ - - def __init__(self, name): - super().__init__(name) - - def tick(self) -> Status: - if len(self.children) != 3 and len(self.children) != 2: - raise ValueError("WhileDoElseNode must have exactly 3 or 2 children") - - condition_node = self.children[0] - do_node = self.children[1] - else_node = self.children[2] if len(self.children) == 3 else None - - condition_status = condition_node.tick_and_set_status() - if condition_status == Status.SUCCESS: - do_node.tick_and_set_status() - return Status.RUNNING - elif condition_status == Status.FAILURE: - if else_node is not None: - else_status = else_node.tick_and_set_status() - if else_status == Status.SUCCESS: - self.reset_children() - return Status.SUCCESS - elif else_status == Status.FAILURE: - self.reset_children() - return Status.FAILURE - elif else_status == Status.RUNNING: - return Status.RUNNING - else: - raise ValueError("Unknown status") - else: - self.reset_children() - return Status.SUCCESS - else: - raise ValueError("Unknown status") - - -class ActionNode(Node): - """ - Base class for all action nodes in a behavior tree. - - Action nodes are responsible for performing specific tasks or actions. - They do not have children and are typically used to execute logic or operations. - """ - - def __init__(self, name): - super().__init__(name) - self.type = NodeType.ACTION_NODE - - -class SleepNode(ActionNode): - """ - Sleep node that sleeps for a specified duration. - - Returns: - Returns SUCCESS after the specified duration has passed - Returns RUNNING if the duration has not yet passed - - Example: - .. code-block:: xml - - <Sleep sec="1.5" /> - """ - - def __init__(self, name, duration): - super().__init__(name) - self.duration = duration - self.start_time = None - - def tick(self) -> Status: - if self.start_time is None: - self.start_time = time.time() - if time.time() - self.start_time > self.duration: - return Status.SUCCESS - return Status.RUNNING - - -class EchoNode(ActionNode): - """ - Echo node that prints a message to the console. - - Returns: - Returns SUCCESS after the message has been printed - - Example: - .. code-block:: xml - - <Echo message="Hello, World!" /> - """ - - def __init__(self, name, message): - super().__init__(name) - self.message = message - - def tick(self) -> Status: - print(self.name, self.message) - return Status.SUCCESS - - -class DecoratorNode(Node): - """ - Base class for all decorator nodes in a behavior tree. - - Decorator nodes modify the behavior of their child node. - They must have a single child and can alter the status of the child node. - """ - - def __init__(self, name): - super().__init__(name) - self.type = NodeType.DECORATOR_NODE - self.child = None - - def not_set_child_raise_error(self): - if self.child is None: - raise ValueError("Child is not set") - - def reset_children(self): - self.child.reset() - - -class InverterNode(DecoratorNode): - """ - Inverter node that inverts the status of its child node. - - Returns: - - Returns SUCCESS if the child returns FAILURE - - Returns FAILURE if the child returns SUCCESS - - Returns RUNNING if the child returns RUNNING - - Examples: - .. code-block:: xml - - <Inverter> - <Action /> - </Inverter> - """ - - def __init__(self, name): - super().__init__(name) - - def tick(self) -> Status: - self.not_set_child_raise_error() - status = self.child.tick_and_set_status() - return Status.SUCCESS if status == Status.FAILURE else Status.FAILURE - - -class TimeoutNode(DecoratorNode): - """ - Timeout node that fails if the child node takes too long to execute - - Returns: - - FAILURE: If the timeout duration has been exceeded - - Child's status: Otherwise, passes through the status of the child node - - Example: - .. code-block:: xml - - <Timeout sec="1.5"> - <Action /> - </Timeout> - """ - - def __init__(self, name, timeout): - super().__init__(name) - self.timeout = timeout - self.start_time = None - - def tick(self) -> Status: - self.not_set_child_raise_error() - if self.start_time is None: - self.start_time = time.time() - if time.time() - self.start_time > self.timeout: - return Status.FAILURE - print(f"{self.name} is running") - return self.child.tick_and_set_status() - - -class DelayNode(DecoratorNode): - """ - Delay node that delays the execution of its child node for a specified duration. - - Returns: - - Returns RUNNING if the duration has not yet passed - - Returns child's status after the duration has passed - - Example: - .. code-block:: xml - - <Delay sec="1.5"> - <Action /> - </Delay> - """ - - def __init__(self, name, delay): - super().__init__(name) - self.delay = delay - self.start_time = None - - def tick(self) -> Status: - self.not_set_child_raise_error() - if self.start_time is None: - self.start_time = time.time() - if time.time() - self.start_time > self.delay: - return self.child.tick_and_set_status() - return Status.RUNNING - - -class ForceSuccessNode(DecoratorNode): - """ - ForceSuccess node that always returns SUCCESS. - - Returns: - - Returns RUNNING if the child returns RUNNING - - Returns SUCCESS if the child returns SUCCESS or FAILURE - """ - - def __init__(self, name): - super().__init__(name) - - def tick(self) -> Status: - self.not_set_child_raise_error() - status = self.child.tick_and_set_status() - if status == Status.FAILURE: - return Status.SUCCESS - return status - - -class ForceFailureNode(DecoratorNode): - """ - ForceFailure node that always returns FAILURE. - - Returns: - - Returns RUNNING if the child returns RUNNING - - Returns FAILURE if the child returns SUCCESS or FAILURE - """ - - def __init__(self, name): - super().__init__(name) - - def tick(self) -> Status: - self.not_set_child_raise_error() - status = self.child.tick_and_set_status() - if status == Status.SUCCESS: - return Status.FAILURE - return status - - -class BehaviorTree: - """ - Behavior tree class that manages the execution of a behavior tree. - """ - - def __init__(self, root): - self.root = root - - def tick(self): - """ - Tick once on the behavior tree. - """ - self.root.tick_and_set_status() - - def reset(self): - """ - Reset the behavior tree. - """ - self.root.reset() - - def tick_while_running(self, interval=None, enable_print=True): - """ - Tick the behavior tree while it is running. - - Args: - interval (float, optional): The interval between ticks. Defaults to None. - enable_print (bool, optional): Whether to print the behavior tree. Defaults to True. - """ - while self.root.tick_and_set_status() == Status.RUNNING: - if enable_print: - self.print_tree() - if interval is not None: - time.sleep(interval) - if enable_print: - self.print_tree() - - def to_text(self, root, indent=0): - """ - Recursively convert the behavior tree to a text representation. - """ - current_text = "" - if root.status == Status.RUNNING: - # yellow - current_text = "\033[93m" + root.name + "\033[0m" - elif root.status == Status.SUCCESS: - # green - current_text = "\033[92m" + root.name + "\033[0m" - elif root.status == Status.FAILURE: - # red - current_text = "\033[91m" + root.name + "\033[0m" - else: - current_text = root.name - if root.type == NodeType.CONTROL_NODE: - current_text = " " * indent + "[" + current_text + "]\n" - for child in root.children: - current_text += self.to_text(child, indent + 2) - elif root.type == NodeType.DECORATOR_NODE: - current_text = " " * indent + "(" + current_text + ")\n" - current_text += self.to_text(root.child, indent + 2) - elif root.type == NodeType.ACTION_NODE: - current_text = " " * indent + "<" + current_text + ">\n" - return current_text - - def print_tree(self): - """ - Print the behavior tree. - - Node print format: - Action: <Action> - Decorator: (Decorator) - Control: [Control] - - Node status colors: - Yellow: RUNNING - Green: SUCCESS - Red: FAILURE - """ - text = self.to_text(self.root) - text = text.strip() - print("\033[94m" + "Behavior Tree" + "\033[0m") - print(text) - print("\033[94m" + "Behavior Tree" + "\033[0m") - - -class BehaviorTreeFactory: - """ - Factory class for creating behavior trees from XML strings. - """ - - def __init__(self): - self.node_builders = {} - # Control nodes - self.register_node_builder( - "Sequence", - lambda node: SequenceNode(node.attrib.get("name", SequenceNode.__name__)), - ) - self.register_node_builder( - "Selector", - lambda node: SelectorNode(node.attrib.get("name", SelectorNode.__name__)), - ) - self.register_node_builder( - "WhileDoElse", - lambda node: WhileDoElseNode( - node.attrib.get("name", WhileDoElseNode.__name__) - ), - ) - # Decorator nodes - self.register_node_builder( - "Inverter", - lambda node: InverterNode(node.attrib.get("name", InverterNode.__name__)), - ) - self.register_node_builder( - "Timeout", - lambda node: TimeoutNode( - node.attrib.get("name", SelectorNode.__name__), - float(node.attrib["sec"]), - ), - ) - self.register_node_builder( - "Delay", - lambda node: DelayNode( - node.attrib.get("name", DelayNode.__name__), - float(node.attrib["sec"]), - ), - ) - self.register_node_builder( - "ForceSuccess", - lambda node: ForceSuccessNode( - node.attrib.get("name", ForceSuccessNode.__name__) - ), - ) - self.register_node_builder( - "ForceFailure", - lambda node: ForceFailureNode( - node.attrib.get("name", ForceFailureNode.__name__) - ), - ) - # Action nodes - self.register_node_builder( - "Sleep", - lambda node: SleepNode( - node.attrib.get("name", SleepNode.__name__), - float(node.attrib["sec"]), - ), - ) - self.register_node_builder( - "Echo", - lambda node: EchoNode( - node.attrib.get("name", EchoNode.__name__), - node.attrib["message"], - ), - ) - - def register_node_builder(self, node_name, builder): - """ - Register a builder for a node - - Args: - node_name (str): The name of the node. - builder (function): The builder function. - - Example: - .. code-block:: python - - factory = BehaviorTreeFactory() - factory.register_node_builder( - "MyNode", - lambda node: MyNode( - node.attrib.get("name", MyNode.__name__), - node.attrib["my_param"], - ), - ) - """ - self.node_builders[node_name] = builder - - def build_node(self, node): - """ - Build a node from an XML element. - - Args: - node (Element): The XML element to build the node from. - - Returns: - BehaviorTree Node: the built node - """ - if node.tag in self.node_builders: - root = self.node_builders[node.tag](node) - if root.type == NodeType.CONTROL_NODE: - if len(node) <= 0: - raise ValueError(f"{root.name} Control node must have children") - for child in node: - root.children.append(self.build_node(child)) - elif root.type == NodeType.DECORATOR_NODE: - if len(node) != 1: - raise ValueError( - f"{root.name} Decorator node must have exactly one child" - ) - root.child = self.build_node(node[0]) - elif root.type == NodeType.ACTION_NODE: - if len(node) != 0: - raise ValueError(f"{root.name} Action node must have no children") - return root - else: - raise ValueError(f"Unknown node type: {node.tag}") - - def build_tree(self, xml_string): - """ - Build a behavior tree from an XML string. - - Args: - xml_string (str): The XML string containing the behavior tree. - - Returns: - BehaviorTree: The behavior tree. - """ - xml_tree = ET.fromstring(xml_string) - root = self.build_node(xml_tree) - return BehaviorTree(root) - - def build_tree_from_file(self, file_path): - """ - Build a behavior tree from a file. - - Args: - file_path (str): The path to the file containing the behavior tree. - - Returns: - BehaviorTree: The behavior tree. - """ - with open(file_path) as file: - xml_string = file.read() - return self.build_tree(xml_string) - - -xml_string = """ - <Sequence name="Sequence"> - <Echo name="Echo0" message="Hello, World0!" /> - <Delay name="Delay" sec="1.5"> - <Echo name="Echo1" message="Hello, World1!" /> - </Delay> - <Echo name="Echo2" message="Hello, World2!" /> - </Sequence> - """ - - -def main(): - factory = BehaviorTreeFactory() - tree = factory.build_tree(xml_string) - tree.tick_while_running() - - -if __name__ == "__main__": - main() diff --git a/MissionPlanning/BehaviorTree/robot_behavior_case.py b/MissionPlanning/BehaviorTree/robot_behavior_case.py deleted file mode 100644 index 6c39aa76b24..00000000000 --- a/MissionPlanning/BehaviorTree/robot_behavior_case.py +++ /dev/null @@ -1,247 +0,0 @@ -""" -Robot Behavior Tree Case - -This file demonstrates how to use a behavior tree to control robot behavior. -""" - -from behavior_tree import ( - BehaviorTreeFactory, - Status, - ActionNode, -) -import time -import random -import os - - -class CheckBatteryNode(ActionNode): - """ - Node to check robot battery level - - If battery level is below threshold, returns FAILURE, otherwise returns SUCCESS - """ - - def __init__(self, name, threshold=20): - super().__init__(name) - self.threshold = threshold - self.battery_level = 100 # Initial battery level is 100% - - def tick(self): - # Simulate battery level decreasing - self.battery_level -= random.randint(1, 5) - print(f"Current battery level: {self.battery_level}%") - - if self.battery_level <= self.threshold: - return Status.FAILURE - return Status.SUCCESS - - -class ChargeBatteryNode(ActionNode): - """ - Node to charge the robot's battery - """ - - def __init__(self, name, charge_rate=10): - super().__init__(name) - self.charge_rate = charge_rate - self.charging_time = 0 - - def tick(self): - # Simulate charging process - if self.charging_time == 0: - print("Starting to charge...") - - self.charging_time += 1 - charge_amount = self.charge_rate * self.charging_time - - if charge_amount >= 100: - print("Charging complete! Battery level: 100%") - self.charging_time = 0 - return Status.SUCCESS - else: - print(f"Charging in progress... Battery level: {min(charge_amount, 100)}%") - return Status.RUNNING - - -class MoveToPositionNode(ActionNode): - """ - Node to move to a specified position - """ - - def __init__(self, name, position, move_duration=2): - super().__init__(name) - self.position = position - self.move_duration = move_duration - self.start_time = None - - def tick(self): - if self.start_time is None: - self.start_time = time.time() - print(f"Starting movement to position {self.position}") - - elapsed_time = time.time() - self.start_time - - if elapsed_time >= self.move_duration: - print(f"Arrived at position {self.position}") - self.start_time = None - return Status.SUCCESS - else: - print( - f"Moving to position {self.position}... {int(elapsed_time / self.move_duration * 100)}% complete" - ) - return Status.RUNNING - - -class DetectObstacleNode(ActionNode): - """ - Node to detect obstacles - """ - - def __init__(self, name, obstacle_probability=0.3): - super().__init__(name) - self.obstacle_probability = obstacle_probability - - def tick(self): - # Use random probability to simulate obstacle detection - if random.random() < self.obstacle_probability: - print("Obstacle detected!") - return Status.SUCCESS - else: - print("No obstacle detected") - return Status.FAILURE - - -class AvoidObstacleNode(ActionNode): - """ - Node to avoid obstacles - """ - - def __init__(self, name, avoid_duration=1.5): - super().__init__(name) - self.avoid_duration = avoid_duration - self.start_time = None - - def tick(self): - if self.start_time is None: - self.start_time = time.time() - print("Starting obstacle avoidance...") - - elapsed_time = time.time() - self.start_time - - if elapsed_time >= self.avoid_duration: - print("Obstacle avoidance complete") - self.start_time = None - return Status.SUCCESS - else: - print("Avoiding obstacle...") - return Status.RUNNING - - -class PerformTaskNode(ActionNode): - """ - Node to perform a specific task - """ - - def __init__(self, name, task_name, task_duration=3): - super().__init__(name) - self.task_name = task_name - self.task_duration = task_duration - self.start_time = None - - def tick(self): - if self.start_time is None: - self.start_time = time.time() - print(f"Starting task: {self.task_name}") - - elapsed_time = time.time() - self.start_time - - if elapsed_time >= self.task_duration: - print(f"Task complete: {self.task_name}") - self.start_time = None - return Status.SUCCESS - else: - print( - f"Performing task: {self.task_name}... {int(elapsed_time / self.task_duration * 100)}% complete" - ) - return Status.RUNNING - - -def create_robot_behavior_tree(): - """ - Create robot behavior tree - """ - - factory = BehaviorTreeFactory() - - # Register custom nodes - factory.register_node_builder( - "CheckBattery", - lambda node: CheckBatteryNode( - node.attrib.get("name", "CheckBattery"), - int(node.attrib.get("threshold", "20")), - ), - ) - - factory.register_node_builder( - "ChargeBattery", - lambda node: ChargeBatteryNode( - node.attrib.get("name", "ChargeBattery"), - int(node.attrib.get("charge_rate", "10")), - ), - ) - - factory.register_node_builder( - "MoveToPosition", - lambda node: MoveToPositionNode( - node.attrib.get("name", "MoveToPosition"), - node.attrib.get("position", "Unknown Position"), - float(node.attrib.get("move_duration", "2")), - ), - ) - - factory.register_node_builder( - "DetectObstacle", - lambda node: DetectObstacleNode( - node.attrib.get("name", "DetectObstacle"), - float(node.attrib.get("obstacle_probability", "0.3")), - ), - ) - - factory.register_node_builder( - "AvoidObstacle", - lambda node: AvoidObstacleNode( - node.attrib.get("name", "AvoidObstacle"), - float(node.attrib.get("avoid_duration", "1.5")), - ), - ) - - factory.register_node_builder( - "PerformTask", - lambda node: PerformTaskNode( - node.attrib.get("name", "PerformTask"), - node.attrib.get("task_name", "Unknown Task"), - float(node.attrib.get("task_duration", "3")), - ), - ) - # Read XML from file - xml_path = os.path.join(os.path.dirname(__file__), "robot_behavior_tree.xml") - return factory.build_tree_from_file(xml_path) - - -def main(): - """ - Main function: Create and run the robot behavior tree - """ - print("Creating robot behavior tree...") - tree = create_robot_behavior_tree() - - print("\nStarting robot behavior tree execution...\n") - # Run for a period of time or until completion - - tree.tick_while_running(interval=0.01) - - print("\nBehavior tree execution complete!") - - -if __name__ == "__main__": - main() diff --git a/MissionPlanning/BehaviorTree/robot_behavior_tree.xml b/MissionPlanning/BehaviorTree/robot_behavior_tree.xml deleted file mode 100644 index 0bca76a3ff9..00000000000 --- a/MissionPlanning/BehaviorTree/robot_behavior_tree.xml +++ /dev/null @@ -1,57 +0,0 @@ -<Selector name="Robot Main Controller"> - <!-- Charge battery when power is low --> - <Sequence name="Battery Management"> - <Inverter name="Low Battery Detection"> - <CheckBattery name="Check Battery" threshold="30" /> - </Inverter> - <Echo name="Low Battery Warning" message="Battery level low! Charging needed" /> - <ChargeBattery name="Charge Battery" charge_rate="20" /> - </Sequence> - <!-- Main task sequence --> - <Sequence name="Patrol Task"> - <Echo name="Start Task" message="Starting patrol task" /> - <!-- Move to position A --> - <Sequence name="Move to Position A"> - <MoveToPosition name="Move to A" position="A" move_duration="2" /> - <!-- Handle obstacles --> - <Selector name="Obstacle Handling A"> - <Sequence name="Obstacle Present"> - <DetectObstacle name="Detect Obstacle" obstacle_probability="0.3" /> - <AvoidObstacle name="Avoid Obstacle" avoid_duration="1.5" /> - </Sequence> - <Echo name="No Obstacle" message="Path clear" /> - </Selector> - <PerformTask name="Position A Task" task_name="Check Device Status" task_duration="2" /> - </Sequence> - <!-- Move to position B --> - <Sequence name="Move to Position B"> - <Delay name="Short Wait" sec="1"> - <Echo name="Prepare Movement" message="Preparing to move to next position" /> - </Delay> - <MoveToPosition name="Move to B" position="B" move_duration="3" /> - <!-- Handle obstacles with timeout --> - <Timeout name="Limited Time Obstacle Handling" sec="2"> - <Sequence name="Obstacle Present"> - <DetectObstacle name="Detect Obstacle" obstacle_probability="0.4" /> - <AvoidObstacle name="Avoid Obstacle" avoid_duration="1.8" /> - </Sequence> - </Timeout> - <PerformTask name="Position B Task" task_name="Data Collection" task_duration="2.5" /> - </Sequence> - <!-- Move to position C --> - <WhileDoElse name="Conditional Move to C"> - <CheckBattery name="Check Sufficient Battery" threshold="50" /> - <Sequence name="Perform Position C Task"> - <MoveToPosition name="Move to C" position="C" move_duration="2.5" /> - <ForceSuccess name="Ensure Completion"> - <PerformTask name="Position C Task" task_name="Environment Monitoring" - task_duration="2" /> - </ForceSuccess> - </Sequence> - <Echo name="Skip Position C" message="Insufficient power, skipping position C task" /> - </WhileDoElse> - <Echo name="Complete Patrol" message="Patrol task completed, returning to charging station" /> - <MoveToPosition name="Return to Charging Station" position="Charging Station" - move_duration="4" /> - </Sequence> -</Selector> \ No newline at end of file diff --git a/MissionPlanning/StateMachine/robot_behavior_case.py b/MissionPlanning/StateMachine/robot_behavior_case.py deleted file mode 100644 index 03ee60ae9fd..00000000000 --- a/MissionPlanning/StateMachine/robot_behavior_case.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -A case study of robot behavior using state machine - -author: Wang Zheng (@Aglargil) -""" - -from state_machine import StateMachine - - -class Robot: - def __init__(self): - self.battery = 100 - self.task_progress = 0 - - # Initialize state machine - self.machine = StateMachine("robot_sm", self) - - # Add state transition rules - self.machine.add_transition( - src_state="patrolling", - event="detect_task", - dst_state="executing_task", - guard=None, - action=None, - ) - - self.machine.add_transition( - src_state="executing_task", - event="task_complete", - dst_state="patrolling", - guard=None, - action="reset_task", - ) - - self.machine.add_transition( - src_state="executing_task", - event="low_battery", - dst_state="returning_to_base", - guard="is_battery_low", - ) - - self.machine.add_transition( - src_state="returning_to_base", - event="reach_base", - dst_state="charging", - guard=None, - action=None, - ) - - self.machine.add_transition( - src_state="charging", - event="charge_complete", - dst_state="patrolling", - guard=None, - action="battery_full", - ) - - # Set initial state - self.machine.set_current_state("patrolling") - - def is_battery_low(self): - """Battery level check condition""" - return self.battery < 30 - - def reset_task(self): - """Reset task progress""" - self.task_progress = 0 - print("[Action] Task progress has been reset") - - # Modify state entry callback naming convention (add state_ prefix) - def on_enter_executing_task(self): - print("\n------ Start Executing Task ------") - print(f"Current battery: {self.battery}%") - while self.machine.get_current_state().name == "executing_task": - self.task_progress += 10 - self.battery -= 25 - print( - f"Task progress: {self.task_progress}%, Remaining battery: {self.battery}%" - ) - - if self.task_progress >= 100: - self.machine.process("task_complete") - break - elif self.is_battery_low(): - self.machine.process("low_battery") - break - - def on_enter_returning_to_base(self): - print("\nLow battery, returning to charging station...") - self.machine.process("reach_base") - - def on_enter_charging(self): - print("\n------ Charging ------") - self.battery = 100 - print("Charging complete!") - self.machine.process("charge_complete") - - -# Keep the test section structure the same, only modify the trigger method -if __name__ == "__main__": - robot = Robot() - print(robot.machine.generate_plantuml()) - - print(f"Initial state: {robot.machine.get_current_state().name}") - print("------------") - - # Trigger task detection event - robot.machine.process("detect_task") - - print("\n------------") - print(f"Final state: {robot.machine.get_current_state().name}") diff --git a/MissionPlanning/StateMachine/state_machine.py b/MissionPlanning/StateMachine/state_machine.py deleted file mode 100644 index de72f0f4517..00000000000 --- a/MissionPlanning/StateMachine/state_machine.py +++ /dev/null @@ -1,294 +0,0 @@ -""" -State Machine - -author: Wang Zheng (@Aglargil) - -Ref: - -- [State Machine] -(https://en.wikipedia.org/wiki/Finite-state_machine) -""" - -import string -from urllib.request import urlopen, Request -from base64 import b64encode -from zlib import compress -from io import BytesIO -from collections.abc import Callable -from matplotlib.image import imread -from matplotlib import pyplot as plt - - -def deflate_and_encode(plantuml_text): - """ - zlib compress the plantuml text and encode it for the plantuml server. - - Ref: https://plantuml.com/en/text-encoding - """ - plantuml_alphabet = ( - string.digits + string.ascii_uppercase + string.ascii_lowercase + "-_" - ) - base64_alphabet = ( - string.ascii_uppercase + string.ascii_lowercase + string.digits + "+/" - ) - b64_to_plantuml = bytes.maketrans( - base64_alphabet.encode("utf-8"), plantuml_alphabet.encode("utf-8") - ) - zlibbed_str = compress(plantuml_text.encode("utf-8")) - compressed_string = zlibbed_str[2:-4] - return b64encode(compressed_string).translate(b64_to_plantuml).decode("utf-8") - - -class State: - def __init__(self, name, on_enter=None, on_exit=None): - self.name = name - self.on_enter = on_enter - self.on_exit = on_exit - - def enter(self): - print(f"entering <{self.name}>") - if self.on_enter: - self.on_enter() - - def exit(self): - print(f"exiting <{self.name}>") - if self.on_exit: - self.on_exit() - - -class StateMachine: - def __init__(self, name: str, model=object): - """Initialize the state machine. - - Args: - name (str): Name of the state machine. - model (object, optional): Model object used to automatically look up callback functions - for states and transitions: - State callbacks: Automatically searches for 'on_enter_<state>' and 'on_exit_<state>' methods. - Transition callbacks: When action or guard parameters are strings, looks up corresponding methods in the model. - - Example: - >>> class MyModel: - ... def on_enter_idle(self): - ... print("Entering idle state") - ... def on_exit_idle(self): - ... print("Exiting idle state") - ... def can_start(self): - ... return True - ... def on_start(self): - ... print("Starting operation") - >>> model = MyModel() - >>> machine = StateMachine("my_machine", model) - """ - self._name = name - self._states = {} - self._events = {} - self._transition_table = {} - self._model = model - self._state: State = None - - def _register_event(self, event: str): - self._events[event] = event - - def _get_state(self, name): - return self._states[name] - - def _get_event(self, name): - return self._events[name] - - def _has_event(self, event: str): - return event in self._events - - def add_transition( - self, - src_state: str | State, - event: str, - dst_state: str | State, - guard: str | Callable = None, - action: str | Callable = None, - ) -> None: - """Add a transition to the state machine. - - Args: - src_state (str | State): The source state where the transition begins. - Can be either a state name or a State object. - event (str): The event that triggers this transition. - dst_state (str | State): The destination state where the transition ends. - Can be either a state name or a State object. - guard (str | Callable, optional): Guard condition for the transition. - If callable: Function that returns bool. - If str: Name of a method in the model class. - If returns True: Transition proceeds. - If returns False: Transition is skipped. - action (str | Callable, optional): Action to execute during transition. - If callable: Function to execute. - If str: Name of a method in the model class. - Executed after guard passes and before entering new state. - - Example: - >>> machine.add_transition( - ... src_state="idle", - ... event="start", - ... dst_state="running", - ... guard="can_start", - ... action="on_start" - ... ) - """ - # Convert string parameters to objects if necessary - self.register_state(src_state) - self._register_event(event) - self.register_state(dst_state) - - def get_state_obj(state): - return state if isinstance(state, State) else self._get_state(state) - - def get_callable(func): - return func if callable(func) else getattr(self._model, func, None) - - src_state_obj = get_state_obj(src_state) - dst_state_obj = get_state_obj(dst_state) - - guard_func = get_callable(guard) if guard else None - action_func = get_callable(action) if action else None - self._transition_table[(src_state_obj.name, event)] = ( - dst_state_obj, - guard_func, - action_func, - ) - - def state_transition(self, src_state: State, event: str): - if (src_state.name, event) not in self._transition_table: - raise ValueError( - f"|{self._name}| invalid transition: <{src_state.name}> : [{event}]" - ) - - dst_state, guard, action = self._transition_table[(src_state.name, event)] - - def call_guard(guard): - if callable(guard): - return guard() - else: - return True - - def call_action(action): - if callable(action): - action() - - if call_guard(guard): - call_action(action) - if src_state.name != dst_state.name: - print( - f"|{self._name}| transitioning from <{src_state.name}> to <{dst_state.name}>" - ) - src_state.exit() - self._state = dst_state - dst_state.enter() - else: - print( - f"|{self._name}| skipping transition from <{src_state.name}> to <{dst_state.name}> because guard failed" - ) - - def register_state(self, state: str | State, on_enter=None, on_exit=None): - """Register a state in the state machine. - - Args: - state (str | State): The state to register. Can be either a string (state name) - or a State object. - on_enter (Callable, optional): Callback function to be executed when entering the state. - If state is a string and on_enter is None, it will look for - a method named 'on_enter_<state>' in the model. - on_exit (Callable, optional): Callback function to be executed when exiting the state. - If state is a string and on_exit is None, it will look for - a method named 'on_exit_<state>' in the model. - Example: - >>> machine.register_state("idle", on_enter=on_enter_idle, on_exit=on_exit_idle) - >>> machine.register_state(State("running", on_enter=on_enter_running, on_exit=on_exit_running)) - """ - if isinstance(state, str): - if on_enter is None: - on_enter = getattr(self._model, "on_enter_" + state, None) - if on_exit is None: - on_exit = getattr(self._model, "on_exit_" + state, None) - self._states[state] = State(state, on_enter, on_exit) - return - - self._states[state.name] = state - - def set_current_state(self, state: State | str): - if isinstance(state, str): - self._state = self._get_state(state) - else: - self._state = state - - def get_current_state(self): - return self._state - - def process(self, event: str) -> None: - """Process an event in the state machine. - - Args: - event: Event name. - - Example: - >>> machine.process("start") - """ - if self._state is None: - raise ValueError("State machine is not initialized") - - if self._has_event(event): - self.state_transition(self._state, event) - else: - raise ValueError(f"Invalid event: {event}") - - def generate_plantuml(self) -> str: - """Generate PlantUML state diagram representation of the state machine. - - Returns: - str: PlantUML state diagram code. - """ - if self._state is None: - raise ValueError("State machine is not initialized") - - plant_uml = ["@startuml"] - plant_uml.append("[*] --> " + self._state.name) - - # Generate transitions - for (src_state, event), ( - dst_state, - guard, - action, - ) in self._transition_table.items(): - transition = f"{src_state} --> {dst_state.name} : {event}" - - # Add guard and action if present - conditions = [] - if guard: - guard_name = guard.__name__ if callable(guard) else guard - conditions.append(f"[{guard_name}]") - if action: - action_name = action.__name__ if callable(action) else action - conditions.append(f"/ {action_name}") - - if conditions: - transition += "\\n" + " ".join(conditions) - - plant_uml.append(transition) - - plant_uml.append("@enduml") - plant_uml_text = "\n".join(plant_uml) - - try: - url = f"http://www.plantuml.com/plantuml/img/{deflate_and_encode(plant_uml_text)}" - headers = {"User-Agent": "Mozilla/5.0"} - request = Request(url, headers=headers) - - with urlopen(request) as response: - content = response.read() - - plt.imshow(imread(BytesIO(content), format="png")) - plt.axis("off") - plt.show() - except Exception as e: - print(f"Error showing PlantUML: {e}") - - return plant_uml_text diff --git a/PathPlanning/AStar/a_star.py b/PathPlanning/AStar/a_star.py deleted file mode 100644 index 6d203504327..00000000000 --- a/PathPlanning/AStar/a_star.py +++ /dev/null @@ -1,282 +0,0 @@ -""" - -A* grid planning - -author: Atsushi Sakai(@Atsushi_twi) - Nikos Kanargias (nkana@tee.gr) - -See Wikipedia article (https://en.wikipedia.org/wiki/A*_search_algorithm) - -""" - -import math - -import matplotlib.pyplot as plt - -show_animation = True - - -class AStarPlanner: - - def __init__(self, ox, oy, resolution, rr): - """ - Initialize grid map for a star planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.resolution = resolution - self.rr = rr - self.min_x, self.min_y = 0, 0 - self.max_x, self.max_y = 0, 0 - self.obstacle_map = None - self.x_width, self.y_width = 0, 0 - self.motion = self.get_motion_model() - self.calc_obstacle_map(ox, oy) - - class Node: - def __init__(self, x, y, cost, parent_index): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, sx, sy, gx, gy): - """ - A star path search - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gy: goal y position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - start_node = self.Node(self.calc_xy_index(sx, self.min_x), - self.calc_xy_index(sy, self.min_y), 0.0, -1) - goal_node = self.Node(self.calc_xy_index(gx, self.min_x), - self.calc_xy_index(gy, self.min_y), 0.0, -1) - - open_set, closed_set = dict(), dict() - open_set[self.calc_grid_index(start_node)] = start_node - - while True: - if len(open_set) == 0: - print("Open set is empty..") - break - - c_id = min( - open_set, - key=lambda o: open_set[o].cost + self.calc_heuristic(goal_node, - open_set[ - o])) - current = open_set[c_id] - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_grid_position(current.x, self.min_x), - self.calc_grid_position(current.y, self.min_y), "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit( - 0) if event.key == 'escape' else None]) - if len(closed_set.keys()) % 10 == 0: - plt.pause(0.001) - - if current.x == goal_node.x and current.y == goal_node.y: - print("Find goal") - goal_node.parent_index = current.parent_index - goal_node.cost = current.cost - break - - # Remove the item from the open set - del open_set[c_id] - - # Add it to the closed set - closed_set[c_id] = current - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - node = self.Node(current.x + self.motion[i][0], - current.y + self.motion[i][1], - current.cost + self.motion[i][2], c_id) - n_id = self.calc_grid_index(node) - - # If the node is not safe, do nothing - if not self.verify_node(node): - continue - - if n_id in closed_set: - continue - - if n_id not in open_set: - open_set[n_id] = node # discovered a new node - else: - if open_set[n_id].cost > node.cost: - # This path is the best until now. record it - open_set[n_id] = node - - rx, ry = self.calc_final_path(goal_node, closed_set) - - return rx, ry - - def calc_final_path(self, goal_node, closed_set): - # generate final course - rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], [ - self.calc_grid_position(goal_node.y, self.min_y)] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_set[parent_index] - rx.append(self.calc_grid_position(n.x, self.min_x)) - ry.append(self.calc_grid_position(n.y, self.min_y)) - parent_index = n.parent_index - - return rx, ry - - @staticmethod - def calc_heuristic(n1, n2): - w = 1.0 # weight of heuristic - d = w * math.hypot(n1.x - n2.x, n1.y - n2.y) - return d - - def calc_grid_position(self, index, min_position): - """ - calc grid position - - :param index: - :param min_position: - :return: - """ - pos = index * self.resolution + min_position - return pos - - def calc_xy_index(self, position, min_pos): - return round((position - min_pos) / self.resolution) - - def calc_grid_index(self, node): - return (node.y - self.min_y) * self.x_width + (node.x - self.min_x) - - def verify_node(self, node): - px = self.calc_grid_position(node.x, self.min_x) - py = self.calc_grid_position(node.y, self.min_y) - - if px < self.min_x: - return False - elif py < self.min_y: - return False - elif px >= self.max_x: - return False - elif py >= self.max_y: - return False - - # collision check - if self.obstacle_map[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.min_x = round(min(ox)) - self.min_y = round(min(oy)) - self.max_x = round(max(ox)) - self.max_y = round(max(oy)) - print("min_x:", self.min_x) - print("min_y:", self.min_y) - print("max_x:", self.max_x) - print("max_y:", self.max_y) - - self.x_width = round((self.max_x - self.min_x) / self.resolution) - self.y_width = round((self.max_y - self.min_y) / self.resolution) - print("x_width:", self.x_width) - print("y_width:", self.y_width) - - # obstacle map generation - self.obstacle_map = [[False for _ in range(self.y_width)] - for _ in range(self.x_width)] - for ix in range(self.x_width): - x = self.calc_grid_position(ix, self.min_x) - for iy in range(self.y_width): - y = self.calc_grid_position(iy, self.min_y) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.rr: - self.obstacle_map[ix][iy] = True - break - - @staticmethod - 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 - - -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 = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(i) - for i in range(-10, 40): - ox.append(20.0) - oy.append(i) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "xb") - plt.grid(True) - plt.axis("equal") - - a_star = AStarPlanner(ox, oy, grid_size, robot_radius) - rx, ry = a_star.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.001) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/AStar/a_star_searching_from_two_side.py b/PathPlanning/AStar/a_star_searching_from_two_side.py deleted file mode 100644 index f43cea71b42..00000000000 --- a/PathPlanning/AStar/a_star_searching_from_two_side.py +++ /dev/null @@ -1,369 +0,0 @@ -""" -A* algorithm -Author: Weicent -randomly generate obstacles, start and goal point -searching path from start and end simultaneously -""" - -import numpy as np -import matplotlib.pyplot as plt -import math - -show_animation = True - - -class Node: - """node with properties of g, h, coordinate and parent node""" - - def __init__(self, G=0, H=0, coordinate=None, parent=None): - self.G = G - self.H = H - self.F = G + H - self.parent = parent - self.coordinate = coordinate - - def reset_f(self): - self.F = self.G + self.H - - -def hcost(node_coordinate, goal): - dx = abs(node_coordinate[0] - goal[0]) - dy = abs(node_coordinate[1] - goal[1]) - hcost = dx + dy - return hcost - - -def gcost(fixed_node, update_node_coordinate): - dx = abs(fixed_node.coordinate[0] - update_node_coordinate[0]) - dy = abs(fixed_node.coordinate[1] - update_node_coordinate[1]) - gc = math.hypot(dx, dy) # gc = move from fixed_node to update_node - gcost = fixed_node.G + gc # gcost = move from start point to update_node - return gcost - - -def boundary_and_obstacles(start, goal, top_vertex, bottom_vertex, obs_number): - """ - :param start: start coordinate - :param goal: goal coordinate - :param top_vertex: top right vertex coordinate of boundary - :param bottom_vertex: bottom left vertex coordinate of boundary - :param obs_number: number of obstacles generated in the map - :return: boundary_obstacle array, obstacle list - """ - # below can be merged into a rectangle boundary - ay = list(range(bottom_vertex[1], top_vertex[1])) - ax = [bottom_vertex[0]] * len(ay) - cy = ay - cx = [top_vertex[0]] * len(cy) - bx = list(range(bottom_vertex[0] + 1, top_vertex[0])) - by = [bottom_vertex[1]] * len(bx) - dx = [bottom_vertex[0]] + bx + [top_vertex[0]] - dy = [top_vertex[1]] * len(dx) - - # generate random obstacles - ob_x = np.random.randint(bottom_vertex[0] + 1, - top_vertex[0], obs_number).tolist() - ob_y = np.random.randint(bottom_vertex[1] + 1, - top_vertex[1], obs_number).tolist() - # x y coordinate in certain order for boundary - x = ax + bx + cx + dx - y = ay + by + cy + dy - obstacle = np.vstack((ob_x, ob_y)).T.tolist() - # remove start and goal coordinate in obstacle list - obstacle = [coor for coor in obstacle if coor != start and coor != goal] - obs_array = np.array(obstacle) - bound = np.vstack((x, y)).T - bound_obs = np.vstack((bound, obs_array)) - return bound_obs, obstacle - - -def find_neighbor(node, ob, closed): - # Convert obstacles to a set for faster lookup - ob_set = set(map(tuple, ob.tolist())) - neighbor_set = set() - - # Generate neighbors within the 3x3 grid around the node - for x in range(node.coordinate[0] - 1, node.coordinate[0] + 2): - for y in range(node.coordinate[1] - 1, node.coordinate[1] + 2): - coord = (x, y) - if coord not in ob_set and coord != tuple(node.coordinate): - neighbor_set.add(coord) - - # Define neighbors in cardinal and diagonal directions - top_nei = (node.coordinate[0], node.coordinate[1] + 1) - bottom_nei = (node.coordinate[0], node.coordinate[1] - 1) - left_nei = (node.coordinate[0] - 1, node.coordinate[1]) - right_nei = (node.coordinate[0] + 1, node.coordinate[1]) - lt_nei = (node.coordinate[0] - 1, node.coordinate[1] + 1) - rt_nei = (node.coordinate[0] + 1, node.coordinate[1] + 1) - lb_nei = (node.coordinate[0] - 1, node.coordinate[1] - 1) - rb_nei = (node.coordinate[0] + 1, node.coordinate[1] - 1) - - # Remove neighbors that violate diagonal motion rules - if top_nei in ob_set and left_nei in ob_set: - neighbor_set.discard(lt_nei) - if top_nei in ob_set and right_nei in ob_set: - neighbor_set.discard(rt_nei) - if bottom_nei in ob_set and left_nei in ob_set: - neighbor_set.discard(lb_nei) - if bottom_nei in ob_set and right_nei in ob_set: - neighbor_set.discard(rb_nei) - - # Filter out neighbors that are in the closed set - closed_set = set(map(tuple, closed)) - neighbor_set -= closed_set - - return list(neighbor_set) - - - -def find_node_index(coordinate, node_list): - # find node index in the node list via its coordinate - ind = 0 - for node in node_list: - if node.coordinate == coordinate: - target_node = node - ind = node_list.index(target_node) - break - return ind - - -def find_path(open_list, closed_list, goal, obstacle): - # searching for the path, update open and closed list - # obstacle = obstacle and boundary - flag = len(open_list) - for i in range(flag): - node = open_list[0] - open_coordinate_list = [node.coordinate for node in open_list] - closed_coordinate_list = [node.coordinate for node in closed_list] - temp = find_neighbor(node, obstacle, closed_coordinate_list) - for element in temp: - if element in closed_list: - continue - elif element in open_coordinate_list: - # if node in open list, update g value - ind = open_coordinate_list.index(element) - new_g = gcost(node, element) - if new_g <= open_list[ind].G: - open_list[ind].G = new_g - open_list[ind].reset_f() - open_list[ind].parent = node - else: # new coordinate, create corresponding node - ele_node = Node(coordinate=element, parent=node, - G=gcost(node, element), H=hcost(element, goal)) - open_list.append(ele_node) - open_list.remove(node) - closed_list.append(node) - open_list.sort(key=lambda x: x.F) - return open_list, closed_list - - -def node_to_coordinate(node_list): - # convert node list into coordinate list and array - coordinate_list = [node.coordinate for node in node_list] - return coordinate_list - - -def check_node_coincide(close_ls1, closed_ls2): - """ - :param close_ls1: node closed list for searching from start - :param closed_ls2: node closed list for searching from end - :return: intersect node list for above two - """ - # check if node in close_ls1 intersect with node in closed_ls2 - cl1 = node_to_coordinate(close_ls1) - cl2 = node_to_coordinate(closed_ls2) - intersect_ls = [node for node in cl1 if node in cl2] - return intersect_ls - - -def find_surrounding(coordinate, obstacle): - # find obstacles around node, help to draw the borderline - boundary: list = [] - for x in range(coordinate[0] - 1, coordinate[0] + 2): - for y in range(coordinate[1] - 1, coordinate[1] + 2): - if [x, y] in obstacle: - boundary.append([x, y]) - return boundary - - -def get_border_line(node_closed_ls, obstacle): - # if no path, find border line which confine goal or robot - border: list = [] - coordinate_closed_ls = node_to_coordinate(node_closed_ls) - for coordinate in coordinate_closed_ls: - temp = find_surrounding(coordinate, obstacle) - border = border + temp - border_ary = np.array(border) - return border_ary - - -def get_path(org_list, goal_list, coordinate): - # get path from start to end - path_org: list = [] - path_goal: list = [] - ind = find_node_index(coordinate, org_list) - node = org_list[ind] - while node != org_list[0]: - path_org.append(node.coordinate) - node = node.parent - path_org.append(org_list[0].coordinate) - ind = find_node_index(coordinate, goal_list) - node = goal_list[ind] - while node != goal_list[0]: - path_goal.append(node.coordinate) - node = node.parent - path_goal.append(goal_list[0].coordinate) - path_org.reverse() - path = path_org + path_goal - path = np.array(path) - return path - - -def random_coordinate(bottom_vertex, top_vertex): - # generate random coordinates inside maze - coordinate = [np.random.randint(bottom_vertex[0] + 1, top_vertex[0]), - np.random.randint(bottom_vertex[1] + 1, top_vertex[1])] - return coordinate - - -def draw(close_origin, close_goal, start, end, bound): - # plot the map - if not close_goal.tolist(): # ensure the close_goal not empty - # in case of the obstacle number is really large (>4500), the - # origin is very likely blocked at the first search, and then - # the program is over and the searching from goal to origin - # will not start, which remain the closed_list for goal == [] - # in order to plot the map, add the end coordinate to array - close_goal = np.array([end]) - plt.cla() - plt.gcf().set_size_inches(11, 9, forward=True) - plt.axis('equal') - plt.plot(close_origin[:, 0], close_origin[:, 1], 'oy') - plt.plot(close_goal[:, 0], close_goal[:, 1], 'og') - plt.plot(bound[:, 0], bound[:, 1], 'sk') - plt.plot(end[0], end[1], '*b', label='Goal') - plt.plot(start[0], start[1], '^b', label='Origin') - plt.legend() - plt.pause(0.0001) - - -def draw_control(org_closed, goal_closed, flag, start, end, bound, obstacle): - """ - control the plot process, evaluate if the searching finished - flag == 0 : draw the searching process and plot path - flag == 1 or 2 : start or end is blocked, draw the border line - """ - stop_loop = 0 # stop sign for the searching - org_closed_ls = node_to_coordinate(org_closed) - org_array = np.array(org_closed_ls) - goal_closed_ls = node_to_coordinate(goal_closed) - goal_array = np.array(goal_closed_ls) - path = None - if show_animation: # draw the searching process - draw(org_array, goal_array, start, end, bound) - if flag == 0: - node_intersect = check_node_coincide(org_closed, goal_closed) - if node_intersect: # a path is find - path = get_path(org_closed, goal_closed, node_intersect[0]) - stop_loop = 1 - print('Path found!') - if show_animation: # draw the path - plt.plot(path[:, 0], path[:, 1], '-r') - plt.title('Robot Arrived', size=20, loc='center') - plt.pause(0.01) - plt.show() - elif flag == 1: # start point blocked first - stop_loop = 1 - print('There is no path to the goal! Start point is blocked!') - elif flag == 2: # end point blocked first - stop_loop = 1 - print('There is no path to the goal! End point is blocked!') - if show_animation: # blocked case, draw the border line - info = 'There is no path to the goal!' \ - ' Robot&Goal are split by border' \ - ' shown in red \'x\'!' - if flag == 1: - border = get_border_line(org_closed, obstacle) - plt.plot(border[:, 0], border[:, 1], 'xr') - plt.title(info, size=14, loc='center') - plt.pause(0.01) - plt.show() - elif flag == 2: - border = get_border_line(goal_closed, obstacle) - plt.plot(border[:, 0], border[:, 1], 'xr') - plt.title(info, size=14, loc='center') - plt.pause(0.01) - plt.show() - return stop_loop, path - - -def searching_control(start, end, bound, obstacle): - """manage the searching process, start searching from two side""" - # initial origin node and end node - origin = Node(coordinate=start, H=hcost(start, end)) - goal = Node(coordinate=end, H=hcost(end, start)) - # list for searching from origin to goal - origin_open: list = [origin] - origin_close: list = [] - # list for searching from goal to origin - goal_open = [goal] - goal_close: list = [] - # initial target - target_goal = end - # flag = 0 (not blocked) 1 (start point blocked) 2 (end point blocked) - flag = 0 # init flag - path = None - while True: - # searching from start to end - origin_open, origin_close = \ - find_path(origin_open, origin_close, target_goal, bound) - if not origin_open: # no path condition - flag = 1 # origin node is blocked - draw_control(origin_close, goal_close, flag, start, end, bound, - obstacle) - break - # update target for searching from end to start - target_origin = min(origin_open, key=lambda x: x.F).coordinate - - # searching from end to start - goal_open, goal_close = \ - find_path(goal_open, goal_close, target_origin, bound) - if not goal_open: # no path condition - flag = 2 # goal is blocked - draw_control(origin_close, goal_close, flag, start, end, bound, - obstacle) - break - # update target for searching from start to end - target_goal = min(goal_open, key=lambda x: x.F).coordinate - - # continue searching, draw the process - stop_sign, path = draw_control(origin_close, goal_close, flag, start, - end, bound, obstacle) - if stop_sign: - break - return path - - -def main(obstacle_number=1500): - print(__file__ + ' start!') - - top_vertex = [60, 60] # top right vertex of boundary - bottom_vertex = [0, 0] # bottom left vertex of boundary - - # generate start and goal point randomly - start = random_coordinate(bottom_vertex, top_vertex) - end = random_coordinate(bottom_vertex, top_vertex) - - # generate boundary and obstacles - bound, obstacle = boundary_and_obstacles(start, end, top_vertex, - bottom_vertex, - obstacle_number) - - path = searching_control(start, end, bound, obstacle) - if not show_animation: - print(path) - - -if __name__ == '__main__': - main(obstacle_number=1500) diff --git a/PathPlanning/AStar/a_star_variants.py b/PathPlanning/AStar/a_star_variants.py deleted file mode 100644 index e0053ee2249..00000000000 --- a/PathPlanning/AStar/a_star_variants.py +++ /dev/null @@ -1,483 +0,0 @@ -""" -a star variants -author: Sarim Mehdi(muhammadsarim.mehdi@studio.unibo.it) -Source: http://theory.stanford.edu/~amitp/GameProgramming/Variations.html -""" - -import numpy as np -import matplotlib.pyplot as plt - -show_animation = True -use_beam_search = False -use_iterative_deepening = False -use_dynamic_weighting = False -use_theta_star = False -use_jump_point = False - -beam_capacity = 30 -max_theta = 5 -only_corners = False -max_corner = 5 -w, epsilon, upper_bound_depth = 1, 4, 500 - - -def draw_horizontal_line(start_x, start_y, length, o_x, o_y, o_dict): - for i in range(start_x, start_x + length): - for j in range(start_y, start_y + 2): - o_x.append(i) - o_y.append(j) - o_dict[(i, j)] = True - - -def draw_vertical_line(start_x, start_y, length, o_x, o_y, o_dict): - for i in range(start_x, start_x + 2): - for j in range(start_y, start_y + length): - o_x.append(i) - o_y.append(j) - o_dict[(i, j)] = True - - -def in_line_of_sight(obs_grid, x1, y1, x2, y2): - t = 0 - while t <= 0.5: - xt = (1 - t) * x1 + t * x2 - yt = (1 - t) * y1 + t * y2 - if obs_grid[(int(xt), int(yt))]: - return False, None - xt = (1 - t) * x2 + t * x1 - yt = (1 - t) * y2 + t * y1 - if obs_grid[(int(xt), int(yt))]: - return False, None - t += 0.001 - dist = np.linalg.norm(np.array([x1, y1] - np.array([x2, y2]))) - return True, dist - - -def key_points(o_dict): - offsets1 = [(1, 0), (0, 1), (-1, 0), (1, 0)] - offsets2 = [(1, 1), (-1, 1), (-1, -1), (1, -1)] - offsets3 = [(0, 1), (-1, 0), (0, -1), (0, -1)] - c_list = [] - for grid_point, obs_status in o_dict.items(): - if obs_status: - continue - empty_space = True - x, y = grid_point - for i in [-1, 0, 1]: - for j in [-1, 0, 1]: - if (x + i, y + j) not in o_dict.keys(): - continue - if o_dict[(x + i, y + j)]: - empty_space = False - break - if empty_space: - continue - for offset1, offset2, offset3 in zip(offsets1, offsets2, offsets3): - i1, j1 = offset1 - i2, j2 = offset2 - i3, j3 = offset3 - if ((x + i1, y + j1) not in o_dict.keys()) or \ - ((x + i2, y + j2) not in o_dict.keys()) or \ - ((x + i3, y + j3) not in o_dict.keys()): - continue - obs_count = 0 - if o_dict[(x + i1, y + j1)]: - obs_count += 1 - if o_dict[(x + i2, y + j2)]: - obs_count += 1 - if o_dict[(x + i3, y + j3)]: - obs_count += 1 - if obs_count == 3 or obs_count == 1: - c_list.append((x, y)) - if show_animation: - plt.plot(x, y, ".y") - break - if only_corners: - return c_list - - e_list = [] - for corner in c_list: - x1, y1 = corner - for other_corner in c_list: - x2, y2 = other_corner - if x1 == x2 and y1 == y2: - continue - reachable, _ = in_line_of_sight(o_dict, x1, y1, x2, y2) - if not reachable: - continue - x_m, y_m = int((x1 + x2) / 2), int((y1 + y2) / 2) - e_list.append((x_m, y_m)) - if show_animation: - plt.plot(x_m, y_m, ".y") - return c_list + e_list - - -class SearchAlgo: - def __init__(self, obs_grid, goal_x, goal_y, start_x, start_y, - limit_x, limit_y, corner_list=None): - self.start_pt = [start_x, start_y] - self.goal_pt = [goal_x, goal_y] - self.obs_grid = obs_grid - g_cost, h_cost = 0, self.get_hval(start_x, start_y, goal_x, goal_y) - f_cost = g_cost + h_cost - self.all_nodes, self.open_set = {}, [] - - if use_jump_point: - for corner in corner_list: - i, j = corner - h_c = self.get_hval(i, j, goal_x, goal_y) - self.all_nodes[(i, j)] = {'pos': [i, j], 'pred': None, - 'gcost': np.inf, 'hcost': h_c, - 'fcost': np.inf, - 'open': True, 'in_open_list': False} - self.all_nodes[tuple(self.goal_pt)] = \ - {'pos': self.goal_pt, 'pred': None, - 'gcost': np.inf, 'hcost': 0, 'fcost': np.inf, - 'open': True, 'in_open_list': True} - else: - for i in range(limit_x): - for j in range(limit_y): - h_c = self.get_hval(i, j, goal_x, goal_y) - self.all_nodes[(i, j)] = {'pos': [i, j], 'pred': None, - 'gcost': np.inf, 'hcost': h_c, - 'fcost': np.inf, - 'open': True, - 'in_open_list': False} - self.all_nodes[tuple(self.start_pt)] = \ - {'pos': self.start_pt, 'pred': None, - 'gcost': g_cost, 'hcost': h_cost, 'fcost': f_cost, - 'open': True, 'in_open_list': True} - self.open_set.append(self.all_nodes[tuple(self.start_pt)]) - - @staticmethod - def get_hval(x1, y1, x2, y2): - x, y = x1, y1 - val = 0 - while x != x2 or y != y2: - if x != x2 and y != y2: - val += 14 - else: - val += 10 - x, y = x + np.sign(x2 - x), y + np.sign(y2 - y) - return val - - def get_farthest_point(self, x, y, i, j): - i_temp, j_temp = i, j - counter = 1 - got_goal = False - while not self.obs_grid[(x + i_temp, y + j_temp)] and \ - counter < max_theta: - i_temp += i - j_temp += j - counter += 1 - if [x + i_temp, y + j_temp] == self.goal_pt: - got_goal = True - break - if (x + i_temp, y + j_temp) not in self.obs_grid.keys(): - break - return i_temp - 2*i, j_temp - 2*j, counter, got_goal - - def jump_point(self): - """Jump point: Instead of exploring all empty spaces of the - map, just explore the corners.""" - - goal_found = False - while len(self.open_set) > 0: - self.open_set = sorted(self.open_set, key=lambda x: x['fcost']) - lowest_f = self.open_set[0]['fcost'] - lowest_h = self.open_set[0]['hcost'] - lowest_g = self.open_set[0]['gcost'] - p = 0 - for p_n in self.open_set[1:]: - if p_n['fcost'] == lowest_f and \ - p_n['gcost'] < lowest_g: - lowest_g = p_n['gcost'] - p += 1 - elif p_n['fcost'] == lowest_f and \ - p_n['gcost'] == lowest_g and \ - p_n['hcost'] < lowest_h: - lowest_h = p_n['hcost'] - p += 1 - else: - break - current_node = self.all_nodes[tuple(self.open_set[p]['pos'])] - x1, y1 = current_node['pos'] - - for cand_pt, cand_node in self.all_nodes.items(): - x2, y2 = cand_pt - if x1 == x2 and y1 == y2: - continue - if np.linalg.norm(np.array([x1, y1] - - np.array([x2, y2]))) > max_corner: - continue - reachable, offset = in_line_of_sight(self.obs_grid, x1, - y1, x2, y2) - if not reachable: - continue - - if list(cand_pt) == self.goal_pt: - current_node['open'] = False - self.all_nodes[tuple(cand_pt)]['pred'] = \ - current_node['pos'] - goal_found = True - break - - g_cost = offset + current_node['gcost'] - h_cost = self.all_nodes[cand_pt]['hcost'] - f_cost = g_cost + h_cost - cand_pt = tuple(cand_pt) - if f_cost < self.all_nodes[cand_pt]['fcost']: - self.all_nodes[cand_pt]['pred'] = current_node['pos'] - self.all_nodes[cand_pt]['gcost'] = g_cost - self.all_nodes[cand_pt]['fcost'] = f_cost - if not self.all_nodes[cand_pt]['in_open_list']: - self.open_set.append(self.all_nodes[cand_pt]) - self.all_nodes[cand_pt]['in_open_list'] = True - if show_animation: - plt.plot(cand_pt[0], cand_pt[1], "r*") - - if goal_found: - break - if show_animation: - plt.pause(0.001) - if goal_found: - current_node = self.all_nodes[tuple(self.goal_pt)] - while goal_found: - if current_node['pred'] is None: - break - x = [current_node['pos'][0], current_node['pred'][0]] - y = [current_node['pos'][1], current_node['pred'][1]] - current_node = self.all_nodes[tuple(current_node['pred'])] - if show_animation: - plt.plot(x, y, "b") - plt.pause(0.001) - if goal_found: - break - - current_node['open'] = False - current_node['in_open_list'] = False - if show_animation: - plt.plot(current_node['pos'][0], current_node['pos'][1], "g*") - del self.open_set[p] - current_node['fcost'], current_node['hcost'] = np.inf, np.inf - if show_animation: - plt.title('Jump Point') - plt.show() - - def a_star(self): - """Beam search: Maintain an open list of just 30 nodes. - If more than 30 nodes, then get rid of nodes with high - f values. - Iterative deepening: At every iteration, get a cut-off - value for the f cost. This cut-off is minimum of the f - value of all nodes whose f value is higher than the - current cut-off value. Nodes with f value higher than - the current cut off value are not put in the open set. - Dynamic weighting: Multiply heuristic with the following: - (1 + epsilon - (epsilon*d)/N) where d is the current - iteration of loop and N is upper bound on number of - iterations. - Theta star: Same as A star but you don't need to move - one neighbor at a time. In fact, you can look for the - next node as far out as you can as long as there is a - clear line of sight from your current node to that node.""" - if show_animation: - if use_beam_search: - plt.title('A* with beam search') - elif use_iterative_deepening: - plt.title('A* with iterative deepening') - elif use_dynamic_weighting: - plt.title('A* with dynamic weighting') - elif use_theta_star: - plt.title('Theta*') - else: - plt.title('A*') - - goal_found = False - curr_f_thresh = np.inf - depth = 0 - no_valid_f = False - w = None - while len(self.open_set) > 0: - self.open_set = sorted(self.open_set, key=lambda x: x['fcost']) - lowest_f = self.open_set[0]['fcost'] - lowest_h = self.open_set[0]['hcost'] - lowest_g = self.open_set[0]['gcost'] - p = 0 - for p_n in self.open_set[1:]: - if p_n['fcost'] == lowest_f and \ - p_n['gcost'] < lowest_g: - lowest_g = p_n['gcost'] - p += 1 - elif p_n['fcost'] == lowest_f and \ - p_n['gcost'] == lowest_g and \ - p_n['hcost'] < lowest_h: - lowest_h = p_n['hcost'] - p += 1 - else: - break - current_node = self.all_nodes[tuple(self.open_set[p]['pos'])] - - while len(self.open_set) > beam_capacity and use_beam_search: - del self.open_set[-1] - - f_cost_list = [] - if use_dynamic_weighting: - w = (1 + epsilon - epsilon*depth/upper_bound_depth) - for i in range(-1, 2): - for j in range(-1, 2): - x, y = current_node['pos'] - if (i == 0 and j == 0) or \ - ((x + i, y + j) not in self.obs_grid.keys()): - continue - if (i, j) in [(1, 0), (0, 1), (-1, 0), (0, -1)]: - offset = 10 - else: - offset = 14 - if use_theta_star: - new_i, new_j, counter, goal_found = \ - self.get_farthest_point(x, y, i, j) - offset = offset * counter - cand_pt = [current_node['pos'][0] + new_i, - current_node['pos'][1] + new_j] - else: - cand_pt = [current_node['pos'][0] + i, - current_node['pos'][1] + j] - - if use_theta_star and goal_found: - current_node['open'] = False - cand_pt = self.goal_pt - self.all_nodes[tuple(cand_pt)]['pred'] = \ - current_node['pos'] - break - - if cand_pt == self.goal_pt: - current_node['open'] = False - self.all_nodes[tuple(cand_pt)]['pred'] = \ - current_node['pos'] - goal_found = True - break - - cand_pt = tuple(cand_pt) - no_valid_f = self.update_node_cost(cand_pt, curr_f_thresh, - current_node, - f_cost_list, no_valid_f, - offset, w) - if goal_found: - break - if show_animation: - plt.pause(0.001) - if goal_found: - current_node = self.all_nodes[tuple(self.goal_pt)] - while goal_found: - if current_node['pred'] is None: - break - if use_theta_star or use_jump_point: - x, y = [current_node['pos'][0], current_node['pred'][0]], \ - [current_node['pos'][1], current_node['pred'][1]] - if show_animation: - plt.plot(x, y, "b") - else: - if show_animation: - plt.plot(current_node['pred'][0], - current_node['pred'][1], "b*") - current_node = self.all_nodes[tuple(current_node['pred'])] - if goal_found: - break - - if use_iterative_deepening and f_cost_list: - curr_f_thresh = min(f_cost_list) - if use_iterative_deepening and not f_cost_list: - curr_f_thresh = np.inf - if use_iterative_deepening and not f_cost_list and no_valid_f: - current_node['fcost'], current_node['hcost'] = np.inf, np.inf - continue - - current_node['open'] = False - current_node['in_open_list'] = False - if show_animation: - plt.plot(current_node['pos'][0], current_node['pos'][1], "g*") - del self.open_set[p] - current_node['fcost'], current_node['hcost'] = np.inf, np.inf - depth += 1 - if show_animation: - plt.show() - - def update_node_cost(self, cand_pt, curr_f_thresh, current_node, - f_cost_list, no_valid_f, offset, w): - if not self.obs_grid[tuple(cand_pt)] and \ - self.all_nodes[cand_pt]['open']: - g_cost = offset + current_node['gcost'] - h_cost = self.all_nodes[cand_pt]['hcost'] - if use_dynamic_weighting: - h_cost = h_cost * w - f_cost = g_cost + h_cost - if f_cost < self.all_nodes[cand_pt]['fcost'] and \ - f_cost <= curr_f_thresh: - f_cost_list.append(f_cost) - self.all_nodes[cand_pt]['pred'] = \ - current_node['pos'] - self.all_nodes[cand_pt]['gcost'] = g_cost - self.all_nodes[cand_pt]['fcost'] = f_cost - if not self.all_nodes[cand_pt]['in_open_list']: - self.open_set.append(self.all_nodes[cand_pt]) - self.all_nodes[cand_pt]['in_open_list'] = True - if show_animation: - plt.plot(cand_pt[0], cand_pt[1], "r*") - if curr_f_thresh < f_cost < \ - self.all_nodes[cand_pt]['fcost']: - no_valid_f = True - return no_valid_f - - -def main(): - # set obstacle positions - obs_dict = {} - for i in range(51): - for j in range(51): - obs_dict[(i, j)] = False - o_x, o_y = [], [] - - s_x = 5.0 - s_y = 5.0 - g_x = 35.0 - g_y = 45.0 - - # draw outer border of maze - draw_vertical_line(0, 0, 50, o_x, o_y, obs_dict) - draw_vertical_line(48, 0, 50, o_x, o_y, obs_dict) - draw_horizontal_line(0, 0, 50, o_x, o_y, obs_dict) - draw_horizontal_line(0, 48, 50, o_x, o_y, obs_dict) - - # draw inner walls - all_x = [10, 10, 10, 15, 20, 20, 30, 30, 35, 30, 40, 45] - all_y = [10, 30, 45, 20, 5, 40, 10, 40, 5, 40, 10, 25] - all_len = [10, 10, 5, 10, 10, 5, 20, 10, 25, 10, 35, 15] - for x, y, l in zip(all_x, all_y, all_len): - draw_vertical_line(x, y, l, o_x, o_y, obs_dict) - - all_x[:], all_y[:], all_len[:] = [], [], [] - all_x = [35, 40, 15, 10, 45, 20, 10, 15, 25, 45, 10, 30, 10, 40] - all_y = [5, 10, 15, 20, 20, 25, 30, 35, 35, 35, 40, 40, 45, 45] - all_len = [10, 5, 10, 10, 5, 5, 10, 5, 10, 5, 10, 5, 5, 5] - for x, y, l in zip(all_x, all_y, all_len): - draw_horizontal_line(x, y, l, o_x, o_y, obs_dict) - - if show_animation: - plt.plot(o_x, o_y, ".k") - plt.plot(s_x, s_y, "og") - plt.plot(g_x, g_y, "xb") - plt.grid(True) - - if use_jump_point: - keypoint_list = key_points(obs_dict) - search_obj = SearchAlgo(obs_dict, g_x, g_y, s_x, s_y, 101, 101, - keypoint_list) - search_obj.jump_point() - else: - search_obj = SearchAlgo(obs_dict, g_x, g_y, s_x, s_y, 101, 101) - search_obj.a_star() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/BSplinePath/bspline_path.py b/PathPlanning/BSplinePath/bspline_path.py deleted file mode 100644 index a2a396efaa7..00000000000 --- a/PathPlanning/BSplinePath/bspline_path.py +++ /dev/null @@ -1,152 +0,0 @@ -""" - -Path Planner with B-Spline - -author: Atsushi Sakai (@Atsushi_twi) - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import numpy as np -import matplotlib.pyplot as plt -import scipy.interpolate as interpolate - -from utils.plot import plot_curvature - - -def approximate_b_spline_path(x: list, - y: list, - n_path_points: int, - degree: int = 3, - s=None, - ) -> tuple: - """ - Approximate points with a B-Spline path - - Parameters - ---------- - x : array_like - x position list of approximated points - y : array_like - y position list of approximated points - n_path_points : int - number of path points - degree : int, optional - B Spline curve degree. Must be 2<= k <= 5. Default: 3. - s : int, optional - smoothing parameter. If this value is bigger, the path will be - smoother, but it will be less accurate. If this value is smaller, - the path will be more accurate, but it will be less smooth. - When `s` is 0, it is equivalent to the interpolation. Default is None, - in this case `s` will be `len(x)`. - - Returns - ------- - x : array - x positions of the result path - y : array - y positions of the result path - heading : array - heading of the result path - curvature : array - curvature of the result path - - """ - distances = _calc_distance_vector(x, y) - - spl_i_x = interpolate.UnivariateSpline(distances, x, k=degree, s=s) - spl_i_y = interpolate.UnivariateSpline(distances, y, k=degree, s=s) - - sampled = np.linspace(0.0, distances[-1], n_path_points) - return _evaluate_spline(sampled, spl_i_x, spl_i_y) - - -def interpolate_b_spline_path(x, y, - n_path_points: int, - degree: int = 3) -> tuple: - """ - Interpolate x-y points with a B-Spline path - - Parameters - ---------- - x : array_like - x positions of interpolated points - y : array_like - y positions of interpolated points - n_path_points : int - number of path points - degree : int, optional - B-Spline degree. Must be 2<= k <= 5. Default: 3 - - Returns - ------- - x : array - x positions of the result path - y : array - y positions of the result path - heading : array - heading of the result path - curvature : array - curvature of the result path - - """ - return approximate_b_spline_path(x, y, n_path_points, degree, s=0.0) - - -def _calc_distance_vector(x, y): - dx, dy = np.diff(x), np.diff(y) - distances = np.cumsum([np.hypot(idx, idy) for idx, idy in zip(dx, dy)]) - distances = np.concatenate(([0.0], distances)) - distances /= distances[-1] - return distances - - -def _evaluate_spline(sampled, spl_i_x, spl_i_y): - x = spl_i_x(sampled) - y = spl_i_y(sampled) - dx = spl_i_x.derivative(1)(sampled) - dy = spl_i_y.derivative(1)(sampled) - heading = np.arctan2(dy, dx) - ddx = spl_i_x.derivative(2)(sampled) - ddy = spl_i_y.derivative(2)(sampled) - curvature = (ddy * dx - ddx * dy) / np.power(dx * dx + dy * dy, 2.0 / 3.0) - return np.array(x), y, heading, curvature, - - -def main(): - print(__file__ + " start!!") - # way points - way_point_x = [-1.0, 3.0, 4.0, 2.0, 1.0] - way_point_y = [0.0, -3.0, 1.0, 1.0, 3.0] - n_course_point = 50 # sampling number - - plt.subplots() - rax, ray, heading, curvature = approximate_b_spline_path( - way_point_x, way_point_y, n_course_point, s=0.5) - plt.plot(rax, ray, '-r', label="Approximated B-Spline path") - plot_curvature(rax, ray, heading, curvature) - - plt.title("B-Spline approximation") - plt.plot(way_point_x, way_point_y, '-og', label="way points") - plt.grid(True) - plt.legend() - plt.axis("equal") - - plt.subplots() - rix, riy, heading, curvature = interpolate_b_spline_path( - way_point_x, way_point_y, n_course_point) - plt.plot(rix, riy, '-b', label="Interpolated B-Spline path") - plot_curvature(rix, riy, heading, curvature) - - plt.title("B-Spline interpolation") - plt.plot(way_point_x, way_point_y, '-og', label="way points") - plt.grid(True) - plt.legend() - plt.axis("equal") - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/BatchInformedRRTStar/batch_informed_rrtstar.py b/PathPlanning/BatchInformedRRTStar/batch_informed_rrtstar.py deleted file mode 100644 index 92c3a58761a..00000000000 --- a/PathPlanning/BatchInformedRRTStar/batch_informed_rrtstar.py +++ /dev/null @@ -1,635 +0,0 @@ -""" -Batch Informed Trees based path planning: -Uses a heuristic to efficiently search increasingly dense -RGGs while reusing previous information. Provides faster -convergence that RRT*, Informed RRT* and other sampling based -methods. - -Uses lazy connecting by combining sampling based methods and A* -like incremental graph search algorithms. - -author: Karan Chawla(@karanchawla) - Atsushi Sakai(@Atsushi_twi) - -Reference: https://arxiv.org/abs/1405.5848 -""" - -import math -import random - -import matplotlib.pyplot as plt -import numpy as np - -show_animation = True - - -class RTree: - # Class to represent the explicit tree created - # while sampling through the state space - - def __init__(self, start=None, lowerLimit=None, upperLimit=None, - resolution=1.0): - - if upperLimit is None: - upperLimit = [10, 10] - if lowerLimit is None: - lowerLimit = [0, 0] - if start is None: - start = [0, 0] - self.vertices = dict() - self.edges = [] - self.start = start - self.lowerLimit = lowerLimit - self.upperLimit = upperLimit - self.dimension = len(lowerLimit) - self.num_cells = [0] * self.dimension - self.resolution = resolution - # compute the number of grid cells based on the limits and - # resolution given - for idx in range(self.dimension): - self.num_cells[idx] = np.ceil( - (upperLimit[idx] - lowerLimit[idx]) / resolution) - - vertex_id = self.real_world_to_node_id(start) - self.vertices[vertex_id] = [] - - @staticmethod - def get_root_id(): - # return the id of the root of the tree - return 0 - - def add_vertex(self, vertex): - # add a vertex to the tree - vertex_id = self.real_world_to_node_id(vertex) - self.vertices[vertex_id] = [] - return vertex_id - - def add_edge(self, v, x): - # create an edge between v and x vertices - if (v, x) not in self.edges: - self.edges.append((v, x)) - # since the tree is undirected - self.vertices[v].append(x) - self.vertices[x].append(v) - - def real_coords_to_grid_coord(self, real_coord): - # convert real world coordinates to grid space - # depends on the resolution of the grid - # the output is the same as real world coords if the resolution - # is set to 1 - coord = [0] * self.dimension - for i in range(len(coord)): - start = self.lowerLimit[i] # start of the grid space - coord[i] = int(np.around((real_coord[i] - start) / self.resolution)) - return coord - - def grid_coordinate_to_node_id(self, coord): - # This function maps a grid coordinate to a unique - # node id - nodeId = 0 - for i in range(len(coord) - 1, -1, -1): - product = 1 - for j in range(0, i): - product = product * self.num_cells[j] - nodeId = nodeId + coord[i] * product - return nodeId - - def real_world_to_node_id(self, real_coord): - # first convert the given coordinates to grid space and then - # convert the grid space coordinates to a unique node id - return self.grid_coordinate_to_node_id( - self.real_coords_to_grid_coord(real_coord)) - - def grid_coord_to_real_world_coord(self, coord): - # This function maps a grid coordinate in discrete space - # to a configuration in the full configuration space - config = [0] * self.dimension - for i in range(0, len(coord)): - # start of the real world / configuration space - start = self.lowerLimit[i] - # step from the coordinate in the grid - grid_step = self.resolution * coord[i] - config[i] = start + grid_step - return config - - def node_id_to_grid_coord(self, node_id): - # This function maps a node id to the associated - # grid coordinate - coord = [0] * len(self.lowerLimit) - for i in range(len(coord) - 1, -1, -1): - # Get the product of the grid space maximums - prod = 1 - for j in range(0, i): - prod = prod * self.num_cells[j] - coord[i] = np.floor(node_id / prod) - node_id = node_id - (coord[i] * prod) - return coord - - def node_id_to_real_world_coord(self, nid): - # This function maps a node in discrete space to a configuration - # in the full configuration space - return self.grid_coord_to_real_world_coord( - self.node_id_to_grid_coord(nid)) - - -class BITStar: - - def __init__(self, start, goal, - obstacleList, randArea, eta=2.0, - maxIter=80): - self.start = start - self.goal = goal - - self.min_rand = randArea[0] - self.max_rand = randArea[1] - self.max_iIter = maxIter - self.obstacleList = obstacleList - self.startId = None - self.goalId = None - - self.vertex_queue = [] - self.edge_queue = [] - self.samples = dict() - self.g_scores = dict() - self.f_scores = dict() - self.nodes = dict() - self.r = float('inf') - self.eta = eta # tunable parameter - self.unit_ball_measure = 1 - self.old_vertices = [] - - # initialize tree - lowerLimit = [randArea[0], randArea[0]] - upperLimit = [randArea[1], randArea[1]] - self.tree = RTree(start=start, lowerLimit=lowerLimit, - upperLimit=upperLimit, resolution=0.01) - - def setup_planning(self): - self.startId = self.tree.real_world_to_node_id(self.start) - self.goalId = self.tree.real_world_to_node_id(self.goal) - - # add goal to the samples - self.samples[self.goalId] = self.goal - self.g_scores[self.goalId] = float('inf') - self.f_scores[self.goalId] = 0 - - # add the start id to the tree - self.tree.add_vertex(self.start) - self.g_scores[self.startId] = 0 - self.f_scores[self.startId] = self.compute_heuristic_cost( - self.startId, self.goalId) - - # max length we expect to find in our 'informed' sample space, starts as infinite - cBest = self.g_scores[self.goalId] - - # Computing the sampling space - cMin = math.hypot(self.start[0] - self.goal[0], - self.start[1] - self.goal[1]) / 1.5 - xCenter = np.array([[(self.start[0] + self.goal[0]) / 2.0], - [(self.start[1] + self.goal[1]) / 2.0], [0]]) - a1 = np.array([[(self.goal[0] - self.start[0]) / cMin], - [(self.goal[1] - self.start[1]) / cMin], [0]]) - eTheta = math.atan2(a1[1, 0], a1[0, 0]) - # first column of identity matrix transposed - id1_t = np.array([1.0, 0.0, 0.0]).reshape(1, 3) - M = np.dot(a1, id1_t) - U, S, Vh = np.linalg.svd(M, True, True) - C = np.dot(np.dot(U, np.diag( - [1.0, 1.0, np.linalg.det(U) * np.linalg.det(np.transpose(Vh))])), - Vh) - - self.samples.update(self.informed_sample( - 200, cBest, cMin, xCenter, C)) - - return eTheta, cMin, xCenter, C, cBest - - def setup_sample(self, iterations, foundGoal, cMin, xCenter, C, cBest): - - if len(self.vertex_queue) == 0 and len(self.edge_queue) == 0: - print("Batch: ", iterations) - # Using informed rrt star way of computing the samples - self.r = 2.0 - if iterations != 0: - if foundGoal: - # a better way to do this would be to make number of samples - # a function of cMin - m = 200 - self.samples = dict() - self.samples[self.goalId] = self.goal - else: - m = 100 - cBest = self.g_scores[self.goalId] - self.samples.update(self.informed_sample( - m, cBest, cMin, xCenter, C)) - - # make the old vertices the new vertices - self.old_vertices += self.tree.vertices.keys() - # add the vertices to the vertex queue - for nid in self.tree.vertices.keys(): - if nid not in self.vertex_queue: - self.vertex_queue.append(nid) - return cBest - - def plan(self, animation=True): - - eTheta, cMin, xCenter, C, cBest = self.setup_planning() - iterations = 0 - - foundGoal = False - # run until done - while iterations < self.max_iIter: - cBest = self.setup_sample(iterations, - foundGoal, cMin, xCenter, C, cBest) - # expand the best vertices until an edge is better than the vertex - # this is done because the vertex cost represents the lower bound - # on the edge cost - while self.best_vertex_queue_value() <= \ - self.best_edge_queue_value(): - self.expand_vertex(self.best_in_vertex_queue()) - - # add the best edge to the tree - bestEdge = self.best_in_edge_queue() - self.edge_queue.remove(bestEdge) - - # Check if this can improve the current solution - estimatedCostOfVertex = self.g_scores[bestEdge[ - 0]] + self.compute_distance_cost( - bestEdge[0], bestEdge[1]) + self.compute_heuristic_cost( - bestEdge[1], self.goalId) - estimatedCostOfEdge = self.compute_distance_cost( - self.startId, bestEdge[0]) + self.compute_heuristic_cost( - bestEdge[0], bestEdge[1]) + self.compute_heuristic_cost( - bestEdge[1], self.goalId) - actualCostOfEdge = self.g_scores[ - bestEdge[0]] + self.compute_distance_cost( - bestEdge[0], bestEdge[1]) - - f1 = estimatedCostOfVertex < self.g_scores[self.goalId] - f2 = estimatedCostOfEdge < self.g_scores[self.goalId] - f3 = actualCostOfEdge < self.g_scores[self.goalId] - - if f1 and f2 and f3: - # connect this edge - firstCoord = self.tree.node_id_to_real_world_coord( - bestEdge[0]) - secondCoord = self.tree.node_id_to_real_world_coord( - bestEdge[1]) - path = self.connect(firstCoord, secondCoord) - lastEdge = self.tree.real_world_to_node_id(secondCoord) - if path is None or len(path) == 0: - continue - nextCoord = path[len(path) - 1, :] - nextCoordPathId = self.tree.real_world_to_node_id( - nextCoord) - bestEdge = (bestEdge[0], nextCoordPathId) - if bestEdge[1] in self.tree.vertices.keys(): - continue - else: - try: - del self.samples[bestEdge[1]] - except KeyError: - # invalid sample key - pass - eid = self.tree.add_vertex(nextCoord) - self.vertex_queue.append(eid) - if eid == self.goalId or bestEdge[0] == self.goalId or \ - bestEdge[1] == self.goalId: - print("Goal found") - foundGoal = True - - self.tree.add_edge(bestEdge[0], bestEdge[1]) - - g_score = self.compute_distance_cost( - bestEdge[0], bestEdge[1]) - self.g_scores[bestEdge[1]] = g_score + self.g_scores[ - bestEdge[0]] - self.f_scores[ - bestEdge[1]] = g_score + self.compute_heuristic_cost( - bestEdge[1], self.goalId) - self.update_graph() - - # visualize new edge - if animation: - self.draw_graph(xCenter=xCenter, cBest=cBest, - cMin=cMin, eTheta=eTheta, - samples=self.samples.values(), - start=firstCoord, end=secondCoord) - - self.remove_queue(lastEdge, bestEdge) - - else: - print("Nothing good") - self.edge_queue = [] - self.vertex_queue = [] - - iterations += 1 - - print("Finding the path") - return self.find_final_path() - - def find_final_path(self): - plan = [self.goal] - currId = self.goalId - while currId != self.startId: - plan.append(self.tree.node_id_to_real_world_coord(currId)) - try: - currId = self.nodes[currId] - except KeyError: - print("cannot find Path") - return [] - - plan.append(self.start) - plan = plan[::-1] # reverse the plan - - return plan - - def remove_queue(self, lastEdge, bestEdge): - for edge in self.edge_queue: - if edge[1] == bestEdge[1]: - dist_cost = self.compute_distance_cost(edge[1], bestEdge[1]) - if self.g_scores[edge[1]] + dist_cost >= \ - self.g_scores[self.goalId]: - if (lastEdge, bestEdge[1]) in self.edge_queue: - self.edge_queue.remove( - (lastEdge, bestEdge[1])) - - def connect(self, start, end): - # A function which attempts to extend from a start coordinates - # to goal coordinates - steps = int(self.compute_distance_cost( - self.tree.real_world_to_node_id(start), - self.tree.real_world_to_node_id(end)) * 10) - x = np.linspace(start[0], end[0], num=steps) - y = np.linspace(start[1], end[1], num=steps) - for i in range(len(x)): - if self._collision_check(x[i], y[i]): - if i == 0: - return None - # if collision, send path until collision - return np.vstack((x[0:i], y[0:i])).transpose() - - return np.vstack((x, y)).transpose() - - def _collision_check(self, x, y): - for (ox, oy, size) in self.obstacleList: - dx = ox - x - dy = oy - y - d = dx * dx + dy * dy - if d <= size ** 2: - return True # collision - return False - - def compute_heuristic_cost(self, start_id, goal_id): - # Using Manhattan distance as heuristic - start = np.array(self.tree.node_id_to_real_world_coord(start_id)) - goal = np.array(self.tree.node_id_to_real_world_coord(goal_id)) - - return np.linalg.norm(start - goal, 2) - - def compute_distance_cost(self, vid, xid): - # L2 norm distance - start = np.array(self.tree.node_id_to_real_world_coord(vid)) - stop = np.array(self.tree.node_id_to_real_world_coord(xid)) - - return np.linalg.norm(stop - start, 2) - - # Sample free space confined in the radius of ball R - def informed_sample(self, m, cMax, cMin, xCenter, C): - samples = dict() - print("g_Score goal id: ", self.g_scores[self.goalId]) - for i in range(m + 1): - if cMax < float('inf'): - r = [cMax / 2.0, - math.sqrt(cMax ** 2 - cMin ** 2) / 2.0, - math.sqrt(cMax ** 2 - cMin ** 2) / 2.0] - L = np.diag(r) - xBall = self.sample_unit_ball() - rnd = np.dot(np.dot(C, L), xBall) + xCenter - rnd = [rnd[(0, 0)], rnd[(1, 0)]] - random_id = self.tree.real_world_to_node_id(rnd) - samples[random_id] = rnd - else: - rnd = self.sample_free_space() - random_id = self.tree.real_world_to_node_id(rnd) - samples[random_id] = rnd - return samples - - # Sample point in a unit ball - @staticmethod - def sample_unit_ball(): - a = random.random() - b = random.random() - - if b < a: - a, b = b, a - - sample = (b * math.cos(2 * math.pi * a / b), - b * math.sin(2 * math.pi * a / b)) - return np.array([[sample[0]], [sample[1]], [0]]) - - def sample_free_space(self): - rnd = [random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand)] - - return rnd - - def best_vertex_queue_value(self): - if len(self.vertex_queue) == 0: - return float('inf') - values = [self.g_scores[v] - + self.compute_heuristic_cost(v, self.goalId) for v in - self.vertex_queue] - values.sort() - return values[0] - - def best_edge_queue_value(self): - if len(self.edge_queue) == 0: - return float('inf') - # return the best value in the queue by score g_tau[v] + c(v,x) + h(x) - values = [self.g_scores[e[0]] + self.compute_distance_cost(e[0], e[1]) - + self.compute_heuristic_cost(e[1], self.goalId) for e in - self.edge_queue] - values.sort(reverse=True) - return values[0] - - def best_in_vertex_queue(self): - # return the best value in the vertex queue - v_plus_values = [(v, self.g_scores[v] + - self.compute_heuristic_cost(v, self.goalId)) - for v in self.vertex_queue] - v_plus_values = sorted(v_plus_values, key=lambda x: x[1]) - # print(v_plus_values) - return v_plus_values[0][0] - - def best_in_edge_queue(self): - e_and_values = [ - (e[0], e[1], self.g_scores[e[0]] + self.compute_distance_cost( - e[0], e[1]) + self.compute_heuristic_cost(e[1], self.goalId)) - for e in self.edge_queue] - e_and_values = sorted(e_and_values, key=lambda x: x[2]) - - return e_and_values[0][0], e_and_values[0][1] - - def expand_vertex(self, vid): - self.vertex_queue.remove(vid) - - # get the coordinates for given vid - currCoord = np.array(self.tree.node_id_to_real_world_coord(vid)) - - # get the nearest value in vertex for every one in samples where difference is - # less than the radius - neighbors = [] - for sid, s_coord in self.samples.items(): - s_coord = np.array(s_coord) - if np.linalg.norm(s_coord - currCoord, 2) <= self.r and sid != vid: - neighbors.append((sid, s_coord)) - - # add an edge to the edge queue is the path might improve the solution - for neighbor in neighbors: - sid = neighbor[0] - h_cost = self.compute_heuristic_cost(sid, self.goalId) - estimated_f_score = self.compute_distance_cost( - self.startId, vid) + h_cost + self.compute_distance_cost(vid, - sid) - if estimated_f_score < self.g_scores[self.goalId]: - self.edge_queue.append((vid, sid)) - - # add the vertex to the edge queue - self.add_vertex_to_edge_queue(vid, currCoord) - - def add_vertex_to_edge_queue(self, vid, currCoord): - if vid not in self.old_vertices: - neighbors = [] - for v, edges in self.tree.vertices.items(): - if v != vid and (v, vid) not in self.edge_queue and \ - (vid, v) not in self.edge_queue: - v_coord = self.tree.node_id_to_real_world_coord(v) - if np.linalg.norm(currCoord - v_coord, 2) <= self.r: - neighbors.append((vid, v_coord)) - - for neighbor in neighbors: - sid = neighbor[0] - estimated_f_score = self.compute_distance_cost( - self.startId, vid) + self.compute_distance_cost( - vid, sid) + self.compute_heuristic_cost(sid, self.goalId) - if estimated_f_score < self.g_scores[self.goalId] and ( - self.g_scores[vid] + - self.compute_distance_cost(vid, sid)) < \ - self.g_scores[sid]: - self.edge_queue.append((vid, sid)) - - def update_graph(self): - closedSet = [] - openSet = [] - currId = self.startId - openSet.append(currId) - - while len(openSet) != 0: - # get the element with lowest f_score - currId = min(openSet, key=lambda x: self.f_scores[x]) - - # remove element from open set - openSet.remove(currId) - - # Check if we're at the goal - if currId == self.goalId: - break - - if currId not in closedSet: - closedSet.append(currId) - - # find a non visited successor to the current node - successors = self.tree.vertices[currId] - for successor in successors: - if successor in closedSet: - continue - else: - # calculate tentative g score - g_score = self.g_scores[currId] + \ - self.compute_distance_cost(currId, successor) - if successor not in openSet: - # add the successor to open set - openSet.append(successor) - elif g_score >= self.g_scores[successor]: - continue - - # update g and f scores - self.g_scores[successor] = g_score - self.f_scores[ - successor] = g_score + self.compute_heuristic_cost( - successor, self.goalId) - - # store the parent and child - self.nodes[successor] = currId - - def draw_graph(self, xCenter=None, cBest=None, cMin=None, eTheta=None, - samples=None, start=None, end=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - for rnd in samples: - if rnd is not None: - plt.plot(rnd[0], rnd[1], "^k") - if cBest != float('inf'): - self.plot_ellipse(xCenter, cBest, cMin, eTheta) - - if start is not None and end is not None: - plt.plot([start[0], start[1]], [end[0], end[1]], "-g") - - for (ox, oy, size) in self.obstacleList: - plt.plot(ox, oy, "ok", ms=30 * size) - - plt.plot(self.start[0], self.start[1], "xr") - plt.plot(self.goal[0], self.goal[1], "xr") - plt.axis([-2, 15, -2, 15]) - plt.grid(True) - plt.pause(0.01) - - @staticmethod - def plot_ellipse(xCenter, cBest, cMin, eTheta): # pragma: no cover - - a = math.sqrt(cBest ** 2 - cMin ** 2) / 2.0 - b = cBest / 2.0 - angle = math.pi / 2.0 - eTheta - cx = xCenter[0] - cy = xCenter[1] - - t = np.arange(0, 2 * math.pi + 0.1, 0.1) - x = [a * math.cos(it) for it in t] - y = [b * math.sin(it) for it in t] - R = np.array([[math.cos(angle), math.sin(angle)], - [-math.sin(angle), math.cos(angle)]]) - fx = R @ np.array([x, y]) - px = np.array(fx[0, :] + cx).flatten() - py = np.array(fx[1, :] + cy).flatten() - plt.plot(cx, cy, "xc") - plt.plot(px, py, "--c") - - -def main(maxIter=80): - print("Starting Batch Informed Trees Star planning") - obstacleList = [ - (5, 5, 0.5), - (9, 6, 1), - (7, 5, 1), - (1, 5, 1), - (3, 6, 1), - (7, 9, 1) - ] - - bitStar = BITStar(start=[-1, 0], goal=[3, 8], obstacleList=obstacleList, - randArea=[-2, 15], maxIter=maxIter) - path = bitStar.plan(animation=show_animation) - print("Done") - - if show_animation: - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.05) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/BezierPath/bezier_path.py b/PathPlanning/BezierPath/bezier_path.py deleted file mode 100644 index 46faf1f3106..00000000000 --- a/PathPlanning/BezierPath/bezier_path.py +++ /dev/null @@ -1,215 +0,0 @@ -""" - -Path planning with Bezier curve. - -author: Atsushi Sakai(@Atsushi_twi) - -""" - -import matplotlib.pyplot as plt -import numpy as np -import scipy.special - -show_animation = True - - -def calc_4points_bezier_path(sx, sy, syaw, ex, ey, eyaw, offset): - """ - Compute control points and path given start and end position. - - :param sx: (float) x-coordinate of the starting point - :param sy: (float) y-coordinate of the starting point - :param syaw: (float) yaw angle at start - :param ex: (float) x-coordinate of the ending point - :param ey: (float) y-coordinate of the ending point - :param eyaw: (float) yaw angle at the end - :param offset: (float) - :return: (numpy array, numpy array) - """ - dist = np.hypot(sx - ex, sy - ey) / offset - control_points = np.array( - [[sx, sy], - [sx + dist * np.cos(syaw), sy + dist * np.sin(syaw)], - [ex - dist * np.cos(eyaw), ey - dist * np.sin(eyaw)], - [ex, ey]]) - - path = calc_bezier_path(control_points, n_points=100) - - return path, control_points - - -def calc_bezier_path(control_points, n_points=100): - """ - Compute bezier path (trajectory) given control points. - - :param control_points: (numpy array) - :param n_points: (int) number of points in the trajectory - :return: (numpy array) - """ - traj = [] - for t in np.linspace(0, 1, n_points): - traj.append(bezier(t, control_points)) - - return np.array(traj) - - -def bernstein_poly(n, i, t): - """ - Bernstein polynom. - - :param n: (int) polynom degree - :param i: (int) - :param t: (float) - :return: (float) - """ - return scipy.special.comb(n, i) * t ** i * (1 - t) ** (n - i) - - -def bezier(t, control_points): - """ - Return one point on the bezier curve. - - :param t: (float) number in [0, 1] - :param control_points: (numpy array) - :return: (numpy array) Coordinates of the point - """ - n = len(control_points) - 1 - return np.sum([bernstein_poly(n, i, t) * control_points[i] for i in range(n + 1)], axis=0) - - -def bezier_derivatives_control_points(control_points, n_derivatives): - """ - Compute control points of the successive derivatives of a given bezier curve. - - A derivative of a bezier curve is a bezier curve. - See https://pomax.github.io/bezierinfo/#derivatives - for detailed explanations - - :param control_points: (numpy array) - :param n_derivatives: (int) - e.g., n_derivatives=2 -> compute control points for first and second derivatives - :return: ([numpy array]) - """ - w = {0: control_points} - for i in range(n_derivatives): - n = len(w[i]) - w[i + 1] = np.array([(n - 1) * (w[i][j + 1] - w[i][j]) - for j in range(n - 1)]) - return w - - -def curvature(dx, dy, ddx, ddy): - """ - Compute curvature at one point given first and second derivatives. - - :param dx: (float) First derivative along x axis - :param dy: (float) - :param ddx: (float) Second derivative along x axis - :param ddy: (float) - :return: (float) - """ - return (dx * ddy - dy * ddx) / (dx ** 2 + dy ** 2) ** (3 / 2) - - -def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"): # pragma: no cover - """Plot arrow.""" - if not isinstance(x, float): - for (ix, iy, iyaw) in zip(x, y, yaw): - plot_arrow(ix, iy, iyaw) - else: - plt.arrow(x, y, length * np.cos(yaw), length * np.sin(yaw), - fc=fc, ec=ec, head_width=width, head_length=width) - plt.plot(x, y) - - -def main(): - """Plot an example bezier curve.""" - start_x = 10.0 # [m] - start_y = 1.0 # [m] - start_yaw = np.radians(180.0) # [rad] - - end_x = -0.0 # [m] - end_y = -3.0 # [m] - end_yaw = np.radians(-45.0) # [rad] - offset = 3.0 - - path, control_points = calc_4points_bezier_path( - start_x, start_y, start_yaw, end_x, end_y, end_yaw, offset) - - # Note: alternatively, instead of specifying start and end position - # you can directly define n control points and compute the path: - # control_points = np.array([[5., 1.], [-2.78, 1.], [-11.5, -4.5], [-6., -8.]]) - # path = calc_bezier_path(control_points, n_points=100) - - # Display the tangent, normal and radius of cruvature at a given point - t = 0.86 # Number in [0, 1] - x_target, y_target = bezier(t, control_points) - derivatives_cp = bezier_derivatives_control_points(control_points, 2) - point = bezier(t, control_points) - dt = bezier(t, derivatives_cp[1]) - ddt = bezier(t, derivatives_cp[2]) - # Radius of curvature - radius = 1 / curvature(dt[0], dt[1], ddt[0], ddt[1]) - # Normalize derivative - dt /= np.linalg.norm(dt, 2) - tangent = np.array([point, point + dt]) - normal = np.array([point, point + [- dt[1], dt[0]]]) - curvature_center = point + np.array([- dt[1], dt[0]]) * radius - circle = plt.Circle(tuple(curvature_center), radius, - color=(0, 0.8, 0.8), fill=False, linewidth=1) - - assert path.T[0][0] == start_x, "path is invalid" - assert path.T[1][0] == start_y, "path is invalid" - assert path.T[0][-1] == end_x, "path is invalid" - assert path.T[1][-1] == end_y, "path is invalid" - - if show_animation: # pragma: no cover - fig, ax = plt.subplots() - ax.plot(path.T[0], path.T[1], label="Bezier Path") - ax.plot(control_points.T[0], control_points.T[1], - '--o', label="Control Points") - ax.plot(x_target, y_target) - ax.plot(tangent[:, 0], tangent[:, 1], label="Tangent") - ax.plot(normal[:, 0], normal[:, 1], label="Normal") - ax.add_artist(circle) - plot_arrow(start_x, start_y, start_yaw) - plot_arrow(end_x, end_y, end_yaw) - ax.legend() - ax.axis("equal") - ax.grid(True) - plt.show() - - -def main2(): - """Show the effect of the offset.""" - start_x = 10.0 # [m] - start_y = 1.0 # [m] - start_yaw = np.radians(180.0) # [rad] - - end_x = -0.0 # [m] - end_y = -3.0 # [m] - end_yaw = np.radians(-45.0) # [rad] - - for offset in np.arange(1.0, 5.0, 1.0): - path, control_points = calc_4points_bezier_path( - start_x, start_y, start_yaw, end_x, end_y, end_yaw, offset) - assert path.T[0][0] == start_x, "path is invalid" - assert path.T[1][0] == start_y, "path is invalid" - assert path.T[0][-1] == end_x, "path is invalid" - assert path.T[1][-1] == end_y, "path is invalid" - - if show_animation: # pragma: no cover - plt.plot(path.T[0], path.T[1], label="Offset=" + str(offset)) - - if show_animation: # pragma: no cover - plot_arrow(start_x, start_y, start_yaw) - plot_arrow(end_x, end_y, end_yaw) - plt.legend() - plt.axis("equal") - plt.grid(True) - plt.show() - - -if __name__ == '__main__': - main() - # main2() diff --git a/PathPlanning/BidirectionalAStar/bidirectional_a_star.py b/PathPlanning/BidirectionalAStar/bidirectional_a_star.py deleted file mode 100644 index 5387cca1ad9..00000000000 --- a/PathPlanning/BidirectionalAStar/bidirectional_a_star.py +++ /dev/null @@ -1,347 +0,0 @@ -""" - -Bidirectional A* grid planning - -author: Erwin Lejeune (@spida_rwin) - -See Wikipedia article (https://en.wikipedia.org/wiki/Bidirectional_search) - -""" - -import math - -import matplotlib.pyplot as plt - -show_animation = True - - -class BidirectionalAStarPlanner: - - def __init__(self, ox, oy, resolution, rr): - """ - Initialize grid map for a star planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.min_x, self.min_y = None, None - self.max_x, self.max_y = None, None - self.x_width, self.y_width, self.obstacle_map = None, None, None - self.resolution = resolution - self.rr = rr - self.calc_obstacle_map(ox, oy) - self.motion = self.get_motion_model() - - class Node: - def __init__(self, x, y, cost, parent_index): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, sx, sy, gx, gy): - """ - Bidirectional A star path search - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gy: goal y position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - start_node = self.Node(self.calc_xy_index(sx, self.min_x), - self.calc_xy_index(sy, self.min_y), 0.0, -1) - goal_node = self.Node(self.calc_xy_index(gx, self.min_x), - self.calc_xy_index(gy, self.min_y), 0.0, -1) - - open_set_A, closed_set_A = dict(), dict() - open_set_B, closed_set_B = dict(), dict() - open_set_A[self.calc_grid_index(start_node)] = start_node - open_set_B[self.calc_grid_index(goal_node)] = goal_node - - current_A = start_node - current_B = goal_node - meet_point_A, meet_point_B = None, None - - while True: - if len(open_set_A) == 0: - print("Open set A is empty..") - break - - if len(open_set_B) == 0: - print("Open set B is empty..") - break - - c_id_A = min( - open_set_A, - key=lambda o: self.find_total_cost(open_set_A, o, current_B)) - - current_A = open_set_A[c_id_A] - - c_id_B = min( - open_set_B, - key=lambda o: self.find_total_cost(open_set_B, o, current_A)) - - current_B = open_set_B[c_id_B] - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_grid_position(current_A.x, self.min_x), - self.calc_grid_position(current_A.y, self.min_y), - "xc") - plt.plot(self.calc_grid_position(current_B.x, self.min_x), - self.calc_grid_position(current_B.y, self.min_y), - "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if len(closed_set_A.keys()) % 10 == 0: - plt.pause(0.001) - - if current_A.x == current_B.x and current_A.y == current_B.y: - print("Found goal") - meet_point_A = current_A - meet_point_B = current_B - break - - # Remove the item from the open set - del open_set_A[c_id_A] - del open_set_B[c_id_B] - - # Add it to the closed set - closed_set_A[c_id_A] = current_A - closed_set_B[c_id_B] = current_B - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - - c_nodes = [self.Node(current_A.x + self.motion[i][0], - current_A.y + self.motion[i][1], - current_A.cost + self.motion[i][2], - c_id_A), - self.Node(current_B.x + self.motion[i][0], - current_B.y + self.motion[i][1], - current_B.cost + self.motion[i][2], - c_id_B)] - - n_ids = [self.calc_grid_index(c_nodes[0]), - self.calc_grid_index(c_nodes[1])] - - # If the node is not safe, do nothing - continue_ = self.check_nodes_and_sets(c_nodes, closed_set_A, - closed_set_B, n_ids) - - if not continue_[0]: - if n_ids[0] not in open_set_A: - # discovered a new node - open_set_A[n_ids[0]] = c_nodes[0] - else: - if open_set_A[n_ids[0]].cost > c_nodes[0].cost: - # This path is the best until now. record it - open_set_A[n_ids[0]] = c_nodes[0] - - if not continue_[1]: - if n_ids[1] not in open_set_B: - # discovered a new node - open_set_B[n_ids[1]] = c_nodes[1] - else: - if open_set_B[n_ids[1]].cost > c_nodes[1].cost: - # This path is the best until now. record it - open_set_B[n_ids[1]] = c_nodes[1] - - rx, ry = self.calc_final_bidirectional_path( - meet_point_A, meet_point_B, closed_set_A, closed_set_B) - - return rx, ry - - # takes two sets and two meeting nodes and return the optimal path - def calc_final_bidirectional_path(self, n1, n2, setA, setB): - rx_A, ry_A = self.calc_final_path(n1, setA) - rx_B, ry_B = self.calc_final_path(n2, setB) - - rx_A.reverse() - ry_A.reverse() - - rx = rx_A + rx_B - ry = ry_A + ry_B - - return rx, ry - - def calc_final_path(self, goal_node, closed_set): - # generate final course - rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], \ - [self.calc_grid_position(goal_node.y, self.min_y)] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_set[parent_index] - rx.append(self.calc_grid_position(n.x, self.min_x)) - ry.append(self.calc_grid_position(n.y, self.min_y)) - parent_index = n.parent_index - - return rx, ry - - def check_nodes_and_sets(self, c_nodes, closedSet_A, closedSet_B, n_ids): - continue_ = [False, False] - if not self.verify_node(c_nodes[0]) or n_ids[0] in closedSet_A: - continue_[0] = True - - if not self.verify_node(c_nodes[1]) or n_ids[1] in closedSet_B: - continue_[1] = True - - return continue_ - - @staticmethod - def calc_heuristic(n1, n2): - w = 1.0 # weight of heuristic - d = w * math.hypot(n1.x - n2.x, n1.y - n2.y) - return d - - def find_total_cost(self, open_set, lambda_, n1): - g_cost = open_set[lambda_].cost - h_cost = self.calc_heuristic(n1, open_set[lambda_]) - f_cost = g_cost + h_cost - return f_cost - - def calc_grid_position(self, index, min_position): - """ - calc grid position - - :param index: - :param min_position: - :return: - """ - pos = index * self.resolution + min_position - return pos - - def calc_xy_index(self, position, min_pos): - return round((position - min_pos) / self.resolution) - - def calc_grid_index(self, node): - return (node.y - self.min_y) * self.x_width + (node.x - self.min_x) - - def verify_node(self, node): - px = self.calc_grid_position(node.x, self.min_x) - py = self.calc_grid_position(node.y, self.min_y) - - if px < self.min_x: - return False - elif py < self.min_y: - return False - elif px >= self.max_x: - return False - elif py >= self.max_y: - return False - - # collision check - if self.obstacle_map[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.min_x = round(min(ox)) - self.min_y = round(min(oy)) - self.max_x = round(max(ox)) - self.max_y = round(max(oy)) - print("min_x:", self.min_x) - print("min_y:", self.min_y) - print("max_x:", self.max_x) - print("max_y:", self.max_y) - - self.x_width = round((self.max_x - self.min_x) / self.resolution) - self.y_width = round((self.max_y - self.min_y) / self.resolution) - print("x_width:", self.x_width) - print("y_width:", self.y_width) - - # obstacle map generation - self.obstacle_map = [[False for _ in range(self.y_width)] - for _ in range(self.x_width)] - for ix in range(self.x_width): - x = self.calc_grid_position(ix, self.min_x) - for iy in range(self.y_width): - y = self.calc_grid_position(iy, self.min_y) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.rr: - self.obstacle_map[ix][iy] = True - break - - @staticmethod - 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 - - -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 = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(i) - for i in range(-10, 40): - ox.append(20.0) - oy.append(i) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "ob") - plt.grid(True) - plt.axis("equal") - - bidir_a_star = BidirectionalAStarPlanner(ox, oy, grid_size, robot_radius) - rx, ry = bidir_a_star.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(.0001) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/BidirectionalBreadthFirstSearch/bidirectional_breadth_first_search.py b/PathPlanning/BidirectionalBreadthFirstSearch/bidirectional_breadth_first_search.py deleted file mode 100644 index 60a8c5e1704..00000000000 --- a/PathPlanning/BidirectionalBreadthFirstSearch/bidirectional_breadth_first_search.py +++ /dev/null @@ -1,317 +0,0 @@ -""" - -Bidirectional Breadth-First grid planning - -author: Erwin Lejeune (@spida_rwin) - -See Wikipedia article (https://en.wikipedia.org/wiki/Breadth-first_search) - -""" - -import math - -import matplotlib.pyplot as plt - -show_animation = True - - -class BidirectionalBreadthFirstSearchPlanner: - - def __init__(self, ox, oy, resolution, rr): - """ - Initialize grid map for bfs planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.min_x, self.min_y = None, None - self.max_x, self.max_y = None, None - self.x_width, self.y_width, self.obstacle_map = None, None, None - self.resolution = resolution - self.rr = rr - self.calc_obstacle_map(ox, oy) - self.motion = self.get_motion_model() - - class Node: - def __init__(self, x, y, cost, parent_index, parent): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index - self.parent = parent - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, sx, sy, gx, gy): - """ - Bidirectional Breadth First search based planning - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gy: goal y position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - start_node = self.Node(self.calc_xy_index(sx, self.min_x), - self.calc_xy_index(sy, self.min_y), 0.0, -1, - None) - goal_node = self.Node(self.calc_xy_index(gx, self.min_x), - self.calc_xy_index(gy, self.min_y), 0.0, -1, - None) - - open_set_A, closed_set_A = dict(), dict() - open_set_B, closed_set_B = dict(), dict() - open_set_B[self.calc_grid_index(goal_node)] = goal_node - open_set_A[self.calc_grid_index(start_node)] = start_node - - meet_point_A, meet_point_B = None, None - - while True: - if len(open_set_A) == 0: - print("Open set A is empty..") - break - - if len(open_set_B) == 0: - print("Open set B is empty") - break - - current_A = open_set_A.pop(list(open_set_A.keys())[0]) - current_B = open_set_B.pop(list(open_set_B.keys())[0]) - - c_id_A = self.calc_grid_index(current_A) - c_id_B = self.calc_grid_index(current_B) - - closed_set_A[c_id_A] = current_A - closed_set_B[c_id_B] = current_B - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_grid_position(current_A.x, self.min_x), - self.calc_grid_position(current_A.y, self.min_y), - "xc") - plt.plot(self.calc_grid_position(current_B.x, self.min_x), - self.calc_grid_position(current_B.y, self.min_y), - "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if len(closed_set_A.keys()) % 10 == 0: - plt.pause(0.001) - - if c_id_A in closed_set_B: - print("Find goal") - meet_point_A = closed_set_A[c_id_A] - meet_point_B = closed_set_B[c_id_A] - break - - elif c_id_B in closed_set_A: - print("Find goal") - meet_point_A = closed_set_A[c_id_B] - meet_point_B = closed_set_B[c_id_B] - break - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - breakA = False - breakB = False - - node_A = self.Node(current_A.x + self.motion[i][0], - current_A.y + self.motion[i][1], - current_A.cost + self.motion[i][2], - c_id_A, None) - node_B = self.Node(current_B.x + self.motion[i][0], - current_B.y + self.motion[i][1], - current_B.cost + self.motion[i][2], - c_id_B, None) - - n_id_A = self.calc_grid_index(node_A) - n_id_B = self.calc_grid_index(node_B) - - # If the node is not safe, do nothing - if not self.verify_node(node_A): - breakA = True - - if not self.verify_node(node_B): - breakB = True - - if (n_id_A not in closed_set_A) and \ - (n_id_A not in open_set_A) and (not breakA): - node_A.parent = current_A - open_set_A[n_id_A] = node_A - - if (n_id_B not in closed_set_B) and \ - (n_id_B not in open_set_B) and (not breakB): - node_B.parent = current_B - open_set_B[n_id_B] = node_B - - rx, ry = self.calc_final_path_bidir( - meet_point_A, meet_point_B, closed_set_A, closed_set_B) - return rx, ry - - # takes both set and meeting nodes and calculate optimal path - def calc_final_path_bidir(self, n1, n2, setA, setB): - rxA, ryA = self.calc_final_path(n1, setA) - rxB, ryB = self.calc_final_path(n2, setB) - - rxA.reverse() - ryA.reverse() - - rx = rxA + rxB - ry = ryA + ryB - - return rx, ry - - def calc_final_path(self, goal_node, closed_set): - # generate final course - rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], [ - self.calc_grid_position(goal_node.y, self.min_y)] - n = closed_set[goal_node.parent_index] - while n is not None: - rx.append(self.calc_grid_position(n.x, self.min_x)) - ry.append(self.calc_grid_position(n.y, self.min_y)) - n = n.parent - - return rx, ry - - def calc_grid_position(self, index, min_position): - """ - calc grid position - - :param index: - :param min_position: - :return: - """ - pos = index * self.resolution + min_position - return pos - - def calc_xy_index(self, position, min_pos): - return round((position - min_pos) / self.resolution) - - def calc_grid_index(self, node): - return (node.y - self.min_y) * self.x_width + (node.x - self.min_x) - - def verify_node(self, node): - px = self.calc_grid_position(node.x, self.min_x) - py = self.calc_grid_position(node.y, self.min_y) - - if px < self.min_x: - return False - elif py < self.min_y: - return False - elif px >= self.max_x: - return False - elif py >= self.max_y: - return False - - # collision check - if self.obstacle_map[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.min_x = round(min(ox)) - self.min_y = round(min(oy)) - self.max_x = round(max(ox)) - self.max_y = round(max(oy)) - print("min_x:", self.min_x) - print("min_y:", self.min_y) - print("max_x:", self.max_x) - print("max_y:", self.max_y) - - self.x_width = round((self.max_x - self.min_x) / self.resolution) - self.y_width = round((self.max_y - self.min_y) / self.resolution) - print("x_width:", self.x_width) - print("y_width:", self.y_width) - - # obstacle map generation - self.obstacle_map = [[False for _ in range(self.y_width)] - for _ in range(self.x_width)] - for ix in range(self.x_width): - x = self.calc_grid_position(ix, self.min_x) - for iy in range(self.y_width): - y = self.calc_grid_position(iy, self.min_y) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.rr: - self.obstacle_map[ix][iy] = True - break - - @staticmethod - 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 - - -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 = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(i) - for i in range(-10, 40): - ox.append(20.0) - oy.append(i) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "ob") - plt.grid(True) - plt.axis("equal") - - bi_bfs = BidirectionalBreadthFirstSearchPlanner( - ox, oy, grid_size, robot_radius) - rx, ry = bi_bfs.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.01) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/BreadthFirstSearch/breadth_first_search.py b/PathPlanning/BreadthFirstSearch/breadth_first_search.py deleted file mode 100644 index ad994732a55..00000000000 --- a/PathPlanning/BreadthFirstSearch/breadth_first_search.py +++ /dev/null @@ -1,258 +0,0 @@ -""" - -Breadth-First grid planning - -author: Erwin Lejeune (@spida_rwin) - -See Wikipedia article (https://en.wikipedia.org/wiki/Breadth-first_search) - -""" - -import math - -import matplotlib.pyplot as plt - -show_animation = True - - -class BreadthFirstSearchPlanner: - - def __init__(self, ox, oy, reso, rr): - """ - Initialize grid map for bfs planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.reso = reso - self.rr = rr - self.calc_obstacle_map(ox, oy) - self.motion = self.get_motion_model() - - class Node: - def __init__(self, x, y, cost, parent_index, parent): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index - self.parent = parent - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, sx, sy, gx, gy): - """ - Breadth First search based planning - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gy: goal y position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - nstart = self.Node(self.calc_xyindex(sx, self.minx), - self.calc_xyindex(sy, self.miny), 0.0, -1, None) - ngoal = self.Node(self.calc_xyindex(gx, self.minx), - self.calc_xyindex(gy, self.miny), 0.0, -1, None) - - open_set, closed_set = dict(), dict() - open_set[self.calc_grid_index(nstart)] = nstart - - while True: - if len(open_set) == 0: - print("Open set is empty..") - break - - current = open_set.pop(list(open_set.keys())[0]) - - c_id = self.calc_grid_index(current) - - closed_set[c_id] = current - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_grid_position(current.x, self.minx), - self.calc_grid_position(current.y, self.miny), "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: - [exit(0) if event.key == 'escape' - else None]) - if len(closed_set.keys()) % 10 == 0: - plt.pause(0.001) - - if current.x == ngoal.x and current.y == ngoal.y: - print("Find goal") - ngoal.parent_index = current.parent_index - ngoal.cost = current.cost - break - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - node = self.Node(current.x + self.motion[i][0], - current.y + self.motion[i][1], - current.cost + self.motion[i][2], c_id, None) - n_id = self.calc_grid_index(node) - - # If the node is not safe, do nothing - if not self.verify_node(node): - continue - - if (n_id not in closed_set) and (n_id not in open_set): - node.parent = current - open_set[n_id] = node - - rx, ry = self.calc_final_path(ngoal, closed_set) - return rx, ry - - def calc_final_path(self, ngoal, closedset): - # generate final course - rx, ry = [self.calc_grid_position(ngoal.x, self.minx)], [ - self.calc_grid_position(ngoal.y, self.miny)] - n = closedset[ngoal.parent_index] - while n is not None: - rx.append(self.calc_grid_position(n.x, self.minx)) - ry.append(self.calc_grid_position(n.y, self.miny)) - n = n.parent - - return rx, ry - - def calc_grid_position(self, index, minp): - """ - calc grid position - - :param index: - :param minp: - :return: - """ - pos = index * self.reso + minp - return pos - - def calc_xyindex(self, position, min_pos): - return round((position - min_pos) / self.reso) - - def calc_grid_index(self, node): - return (node.y - self.miny) * self.xwidth + (node.x - self.minx) - - def verify_node(self, node): - px = self.calc_grid_position(node.x, self.minx) - py = self.calc_grid_position(node.y, self.miny) - - if px < self.minx: - return False - elif py < self.miny: - return False - elif px >= self.maxx: - return False - elif py >= self.maxy: - return False - - # collision check - if self.obmap[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.minx = round(min(ox)) - self.miny = round(min(oy)) - self.maxx = round(max(ox)) - self.maxy = round(max(oy)) - print("min_x:", self.minx) - print("min_y:", self.miny) - print("max_x:", self.maxx) - print("max_y:", self.maxy) - - self.xwidth = round((self.maxx - self.minx) / self.reso) - self.ywidth = round((self.maxy - self.miny) / self.reso) - print("x_width:", self.xwidth) - print("y_width:", self.ywidth) - - # obstacle map generation - self.obmap = [[False for _ in range(self.ywidth)] - for _ in range(self.xwidth)] - for ix in range(self.xwidth): - x = self.calc_grid_position(ix, self.minx) - for iy in range(self.ywidth): - y = self.calc_grid_position(iy, self.miny) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.rr: - self.obmap[ix][iy] = True - break - - @staticmethod - 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 - - -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 = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(float(i)) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(float(i)) - for i in range(-10, 61): - ox.append(float(i)) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(float(i)) - for i in range(-10, 40): - ox.append(20.0) - oy.append(float(i)) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "xb") - plt.grid(True) - plt.axis("equal") - - bfs = BreadthFirstSearchPlanner(ox, oy, grid_size, robot_radius) - rx, ry = bfs.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.01) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/BugPlanning/bug.py b/PathPlanning/BugPlanning/bug.py deleted file mode 100644 index 34890cb55a9..00000000000 --- a/PathPlanning/BugPlanning/bug.py +++ /dev/null @@ -1,333 +0,0 @@ -""" -Bug Planning -author: Sarim Mehdi(muhammadsarim.mehdi@studio.unibo.it) -Source: https://web.archive.org/web/20201103052224/https://sites.google.com/site/ece452bugalgorithms/ -""" - -import numpy as np -import matplotlib.pyplot as plt - -show_animation = True - - -class BugPlanner: - def __init__(self, start_x, start_y, goal_x, goal_y, obs_x, obs_y): - self.goal_x = goal_x - self.goal_y = goal_y - self.obs_x = obs_x - self.obs_y = obs_y - self.r_x = [start_x] - self.r_y = [start_y] - self.out_x = [] - self.out_y = [] - for o_x, o_y in zip(obs_x, obs_y): - for add_x, add_y in zip([1, 0, -1, -1, -1, 0, 1, 1], - [1, 1, 1, 0, -1, -1, -1, 0]): - cand_x, cand_y = o_x+add_x, o_y+add_y - valid_point = True - for _x, _y in zip(obs_x, obs_y): - if cand_x == _x and cand_y == _y: - valid_point = False - break - if valid_point: - self.out_x.append(cand_x), self.out_y.append(cand_y) - - def mov_normal(self): - return self.r_x[-1] + np.sign(self.goal_x - self.r_x[-1]), \ - self.r_y[-1] + np.sign(self.goal_y - self.r_y[-1]) - - def mov_to_next_obs(self, visited_x, visited_y): - for add_x, add_y in zip([1, 0, -1, 0], [0, 1, 0, -1]): - c_x, c_y = self.r_x[-1] + add_x, self.r_y[-1] + add_y - for _x, _y in zip(self.out_x, self.out_y): - use_pt = True - if c_x == _x and c_y == _y: - for v_x, v_y in zip(visited_x, visited_y): - if c_x == v_x and c_y == v_y: - use_pt = False - break - if use_pt: - return c_x, c_y, False - if not use_pt: - break - return self.r_x[-1], self.r_y[-1], True - - def bug0(self): - """ - Greedy algorithm where you move towards goal - until you hit an obstacle. Then you go around it - (pick an arbitrary direction), until it is possible - for you to start moving towards goal in a greedy manner again - """ - mov_dir = 'normal' - cand_x, cand_y = -np.inf, -np.inf - if show_animation: - plt.plot(self.obs_x, self.obs_y, ".k") - plt.plot(self.r_x[-1], self.r_y[-1], "og") - plt.plot(self.goal_x, self.goal_y, "xb") - plt.plot(self.out_x, self.out_y, ".") - plt.grid(True) - plt.title('BUG 0') - - for x_ob, y_ob in zip(self.out_x, self.out_y): - if self.r_x[-1] == x_ob and self.r_y[-1] == y_ob: - mov_dir = 'obs' - break - - visited_x, visited_y = [], [] - while True: - if self.r_x[-1] == self.goal_x and \ - self.r_y[-1] == self.goal_y: - break - if mov_dir == 'normal': - cand_x, cand_y = self.mov_normal() - if mov_dir == 'obs': - cand_x, cand_y, _ = self.mov_to_next_obs(visited_x, visited_y) - if mov_dir == 'normal': - found_boundary = False - for x_ob, y_ob in zip(self.out_x, self.out_y): - if cand_x == x_ob and cand_y == y_ob: - self.r_x.append(cand_x), self.r_y.append(cand_y) - visited_x[:], visited_y[:] = [], [] - visited_x.append(cand_x), visited_y.append(cand_y) - mov_dir = 'obs' - found_boundary = True - break - if not found_boundary: - self.r_x.append(cand_x), self.r_y.append(cand_y) - elif mov_dir == 'obs': - can_go_normal = True - for x_ob, y_ob in zip(self.obs_x, self.obs_y): - if self.mov_normal()[0] == x_ob and \ - self.mov_normal()[1] == y_ob: - can_go_normal = False - break - if can_go_normal: - mov_dir = 'normal' - else: - self.r_x.append(cand_x), self.r_y.append(cand_y) - visited_x.append(cand_x), visited_y.append(cand_y) - if show_animation: - plt.plot(self.r_x, self.r_y, "-r") - plt.pause(0.001) - if show_animation: - plt.show() - - def bug1(self): - """ - Move towards goal in a greedy manner. - When you hit an obstacle, you go around it and - back to where you hit the obstacle initially. - Then, you go to the point on the obstacle that is - closest to your goal and you start moving towards - goal in a greedy manner from that new point. - """ - mov_dir = 'normal' - cand_x, cand_y = -np.inf, -np.inf - exit_x, exit_y = -np.inf, -np.inf - dist = np.inf - back_to_start = False - second_round = False - if show_animation: - plt.plot(self.obs_x, self.obs_y, ".k") - plt.plot(self.r_x[-1], self.r_y[-1], "og") - plt.plot(self.goal_x, self.goal_y, "xb") - plt.plot(self.out_x, self.out_y, ".") - plt.grid(True) - plt.title('BUG 1') - - for xob, yob in zip(self.out_x, self.out_y): - if self.r_x[-1] == xob and self.r_y[-1] == yob: - mov_dir = 'obs' - break - - visited_x, visited_y = [], [] - while True: - if self.r_x[-1] == self.goal_x and \ - self.r_y[-1] == self.goal_y: - break - if mov_dir == 'normal': - cand_x, cand_y = self.mov_normal() - if mov_dir == 'obs': - cand_x, cand_y, back_to_start = \ - self.mov_to_next_obs(visited_x, visited_y) - if mov_dir == 'normal': - found_boundary = False - for x_ob, y_ob in zip(self.out_x, self.out_y): - if cand_x == x_ob and cand_y == y_ob: - self.r_x.append(cand_x), self.r_y.append(cand_y) - visited_x[:], visited_y[:] = [], [] - visited_x.append(cand_x), visited_y.append(cand_y) - mov_dir = 'obs' - dist = np.inf - back_to_start = False - second_round = False - found_boundary = True - break - if not found_boundary: - self.r_x.append(cand_x), self.r_y.append(cand_y) - elif mov_dir == 'obs': - d = np.linalg.norm(np.array([cand_x, cand_y] - - np.array([self.goal_x, - self.goal_y]))) - if d < dist and not second_round: - exit_x, exit_y = cand_x, cand_y - dist = d - if back_to_start and not second_round: - second_round = True - del self.r_x[-len(visited_x):] - del self.r_y[-len(visited_y):] - visited_x[:], visited_y[:] = [], [] - self.r_x.append(cand_x), self.r_y.append(cand_y) - visited_x.append(cand_x), visited_y.append(cand_y) - if cand_x == exit_x and \ - cand_y == exit_y and \ - second_round: - mov_dir = 'normal' - if show_animation: - plt.plot(self.r_x, self.r_y, "-r") - plt.pause(0.001) - if show_animation: - plt.show() - - def bug2(self): - """ - Move towards goal in a greedy manner. - When you hit an obstacle, you go around it and - keep track of your distance from the goal. - If the distance from your goal was decreasing before - and now it starts increasing, that means the current - point is probably the closest point to the - goal (this may or may not be true because the algorithm - doesn't explore the entire boundary around the obstacle). - So, you depart from this point and continue towards the - goal in a greedy manner - """ - mov_dir = 'normal' - cand_x, cand_y = -np.inf, -np.inf - if show_animation: - plt.plot(self.obs_x, self.obs_y, ".k") - plt.plot(self.r_x[-1], self.r_y[-1], "og") - plt.plot(self.goal_x, self.goal_y, "xb") - plt.plot(self.out_x, self.out_y, ".") - - straight_x, straight_y = [self.r_x[-1]], [self.r_y[-1]] - hit_x, hit_y = [], [] - while True: - if straight_x[-1] == self.goal_x and \ - straight_y[-1] == self.goal_y: - break - c_x = straight_x[-1] + np.sign(self.goal_x - straight_x[-1]) - c_y = straight_y[-1] + np.sign(self.goal_y - straight_y[-1]) - for x_ob, y_ob in zip(self.out_x, self.out_y): - if c_x == x_ob and c_y == y_ob: - hit_x.append(c_x), hit_y.append(c_y) - break - straight_x.append(c_x), straight_y.append(c_y) - if show_animation: - plt.plot(straight_x, straight_y, ",") - plt.plot(hit_x, hit_y, "d") - plt.grid(True) - plt.title('BUG 2') - - for x_ob, y_ob in zip(self.out_x, self.out_y): - if self.r_x[-1] == x_ob and self.r_y[-1] == y_ob: - mov_dir = 'obs' - break - - visited_x, visited_y = [], [] - while True: - if self.r_x[-1] == self.goal_x \ - and self.r_y[-1] == self.goal_y: - break - if mov_dir == 'normal': - cand_x, cand_y = self.mov_normal() - if mov_dir == 'obs': - cand_x, cand_y, _ = self.mov_to_next_obs(visited_x, visited_y) - if mov_dir == 'normal': - found_boundary = False - for x_ob, y_ob in zip(self.out_x, self.out_y): - if cand_x == x_ob and cand_y == y_ob: - self.r_x.append(cand_x), self.r_y.append(cand_y) - visited_x[:], visited_y[:] = [], [] - visited_x.append(cand_x), visited_y.append(cand_y) - del hit_x[0] - del hit_y[0] - mov_dir = 'obs' - found_boundary = True - break - if not found_boundary: - self.r_x.append(cand_x), self.r_y.append(cand_y) - elif mov_dir == 'obs': - self.r_x.append(cand_x), self.r_y.append(cand_y) - visited_x.append(cand_x), visited_y.append(cand_y) - for i_x, i_y in zip(range(len(hit_x)), range(len(hit_y))): - if cand_x == hit_x[i_x] and cand_y == hit_y[i_y]: - del hit_x[i_x] - del hit_y[i_y] - mov_dir = 'normal' - break - if show_animation: - plt.plot(self.r_x, self.r_y, "-r") - plt.pause(0.001) - if show_animation: - plt.show() - - -def main(bug_0, bug_1, bug_2): - # set obstacle positions - o_x, o_y = [], [] - - s_x = 0.0 - s_y = 0.0 - g_x = 167.0 - g_y = 50.0 - - for i in range(20, 40): - for j in range(20, 40): - o_x.append(i) - o_y.append(j) - - for i in range(60, 100): - for j in range(40, 80): - o_x.append(i) - o_y.append(j) - - for i in range(120, 140): - for j in range(80, 100): - o_x.append(i) - o_y.append(j) - - for i in range(80, 140): - for j in range(0, 20): - o_x.append(i) - o_y.append(j) - - for i in range(0, 20): - for j in range(60, 100): - o_x.append(i) - o_y.append(j) - - for i in range(20, 40): - for j in range(80, 100): - o_x.append(i) - o_y.append(j) - - for i in range(120, 160): - for j in range(40, 60): - o_x.append(i) - o_y.append(j) - - if bug_0: - my_Bug = BugPlanner(s_x, s_y, g_x, g_y, o_x, o_y) - my_Bug.bug0() - if bug_1: - my_Bug = BugPlanner(s_x, s_y, g_x, g_y, o_x, o_y) - my_Bug.bug1() - if bug_2: - my_Bug = BugPlanner(s_x, s_y, g_x, g_y, o_x, o_y) - my_Bug.bug2() - - -if __name__ == '__main__': - main(bug_0=True, bug_1=False, bug_2=False) diff --git a/PathPlanning/Catmull_RomSplinePath/blending_functions.py b/PathPlanning/Catmull_RomSplinePath/blending_functions.py deleted file mode 100644 index f3ef5dd3238..00000000000 --- a/PathPlanning/Catmull_RomSplinePath/blending_functions.py +++ /dev/null @@ -1,34 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -def blending_function_1(t): - return -t + 2*t**2 - t**3 - -def blending_function_2(t): - return 2 - 5*t**2 + 3*t**3 - -def blending_function_3(t): - return t + 4*t**2 - 3*t**3 - -def blending_function_4(t): - return -t**2 + t**3 - -def plot_blending_functions(): - t = np.linspace(0, 1, 100) - - plt.plot(t, blending_function_1(t), label='b1') - plt.plot(t, blending_function_2(t), label='b2') - plt.plot(t, blending_function_3(t), label='b3') - plt.plot(t, blending_function_4(t), label='b4') - - plt.title("Catmull-Rom Blending Functions") - plt.xlabel("t") - plt.ylabel("Value") - plt.legend() - plt.grid(True) - plt.axhline(y=0, color='k', linestyle='--') - plt.axvline(x=0, color='k', linestyle='--') - plt.show() - -if __name__ == "__main__": - plot_blending_functions() \ No newline at end of file diff --git a/PathPlanning/Catmull_RomSplinePath/catmull_rom_spline_path.py b/PathPlanning/Catmull_RomSplinePath/catmull_rom_spline_path.py deleted file mode 100644 index 79916330c9b..00000000000 --- a/PathPlanning/Catmull_RomSplinePath/catmull_rom_spline_path.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -Path Planner with Catmull-Rom Spline -Author: Surabhi Gupta (@this_is_surabhi) -Source: http://graphics.cs.cmu.edu/nsp/course/15-462/Fall04/assts/catmullRom.pdf -""" - -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import numpy as np -import matplotlib.pyplot as plt - -def catmull_rom_point(t, p0, p1, p2, p3): - """ - Parameters - ---------- - t : float - Parameter value (0 <= t <= 1) (0 <= t <= 1) - p0, p1, p2, p3 : np.ndarray - Control points for the spline segment - - Returns - ------- - np.ndarray - Calculated point on the spline - """ - return 0.5 * ((2 * p1) + - (-p0 + p2) * t + - (2 * p0 - 5 * p1 + 4 * p2 - p3) * t**2 + - (-p0 + 3 * p1 - 3 * p2 + p3) * t**3) - - -def catmull_rom_spline(control_points, num_points): - """ - Parameters - ---------- - control_points : list - List of control points - num_points : int - Number of points to generate on the spline - - Returns - ------- - tuple - x and y coordinates of the spline points - """ - t_vals = np.linspace(0, 1, num_points) - spline_points = [] - - control_points = np.array(control_points) - - for i in range(len(control_points) - 1): - if i == 0: - p1, p2, p3 = control_points[i:i+3] - p0 = p1 - elif i == len(control_points) - 2: - p0, p1, p2 = control_points[i-1:i+2] - p3 = p2 - else: - p0, p1, p2, p3 = control_points[i-1:i+3] - - for t in t_vals: - point = catmull_rom_point(t, p0, p1, p2, p3) - spline_points.append(point) - - return np.array(spline_points).T - - -def main(): - print(__file__ + " start!!") - - way_points = [[-1.0, -2.0], [1.0, -1.0], [3.0, -2.0], [4.0, -1.0], [3.0, 1.0], [1.0, 2.0], [0.0, 2.0]] - n_course_point = 100 - spline_x, spline_y = catmull_rom_spline(way_points, n_course_point) - - plt.plot(spline_x,spline_y, '-r', label="Catmull-Rom Spline Path") - plt.plot(np.array(way_points).T[0], np.array(way_points).T[1], '-og', label="Way points") - plt.title("Catmull-Rom Spline Path") - plt.grid(True) - plt.legend() - plt.axis("equal") - plt.show() - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/PathPlanning/ClosedLoopRRTStar/closed_loop_rrt_star_car.py b/PathPlanning/ClosedLoopRRTStar/closed_loop_rrt_star_car.py deleted file mode 100644 index 01ab8349a9c..00000000000 --- a/PathPlanning/ClosedLoopRRTStar/closed_loop_rrt_star_car.py +++ /dev/null @@ -1,216 +0,0 @@ -""" - -Path planning Sample Code with Closed loop RRT for car like robot. - -author: AtsushiSakai(@Atsushi_twi) - -""" -import matplotlib.pyplot as plt -import numpy as np - -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from ClosedLoopRRTStar import pure_pursuit -from ClosedLoopRRTStar import unicycle_model -from ReedsSheppPath import reeds_shepp_path_planning -from RRTStarReedsShepp.rrt_star_reeds_shepp import RRTStarReedsShepp - -show_animation = True - - -class ClosedLoopRRTStar(RRTStarReedsShepp): - """ - Class for Closed loop RRT star planning - """ - - def __init__(self, start, goal, obstacle_list, rand_area, - max_iter=200, - connect_circle_dist=50.0, - robot_radius=0.0 - ): - super().__init__(start, goal, obstacle_list, rand_area, - max_iter=max_iter, - connect_circle_dist=connect_circle_dist, - robot_radius=robot_radius - ) - - self.target_speed = 10.0 / 3.6 - self.yaw_th = np.deg2rad(3.0) - self.xy_th = 0.5 - self.invalid_travel_ratio = 5.0 - - def planning(self, animation=True): - """ - do planning - - animation: flag for animation on or off - """ - # planning with RRTStarReedsShepp - super().planning(animation=animation) - - # generate coruse - path_indexs = self.get_goal_indexes() - - flag, x, y, yaw, v, t, a, d = self.search_best_feasible_path( - path_indexs) - - return flag, x, y, yaw, v, t, a, d - - def search_best_feasible_path(self, path_indexs): - - print("Start search feasible path") - - best_time = float("inf") - - fx, fy, fyaw, fv, ft, fa, fd = None, None, None, None, None, None, None - - # pure pursuit tracking - for ind in path_indexs: - path = self.generate_final_course(ind) - - flag, x, y, yaw, v, t, a, d = self.check_tracking_path_is_feasible( - path) - - if flag and best_time >= t[-1]: - print("feasible path is found") - best_time = t[-1] - fx, fy, fyaw, fv, ft, fa, fd = x, y, yaw, v, t, a, d - - print("best time is") - print(best_time) - - if fx: - fx.append(self.end.x) - fy.append(self.end.y) - fyaw.append(self.end.yaw) - return True, fx, fy, fyaw, fv, ft, fa, fd - - return False, None, None, None, None, None, None, None - - def check_tracking_path_is_feasible(self, path): - cx = np.array([state[0] for state in path])[::-1] - cy = np.array([state[1] for state in path])[::-1] - cyaw = np.array([state[2] for state in path])[::-1] - - goal = [cx[-1], cy[-1], cyaw[-1]] - - cx, cy, cyaw = pure_pursuit.extend_path(cx, cy, cyaw) - - speed_profile = pure_pursuit.calc_speed_profile( - cx, cy, cyaw, self.target_speed) - - t, x, y, yaw, v, a, d, find_goal = pure_pursuit.closed_loop_prediction( - cx, cy, cyaw, speed_profile, goal) - yaw = [reeds_shepp_path_planning.pi_2_pi(iyaw) for iyaw in yaw] - - if not find_goal: - print("cannot reach goal") - - if abs(yaw[-1] - goal[2]) >= self.yaw_th * 10.0: - print("final angle is bad") - find_goal = False - - travel = unicycle_model.dt * sum(np.abs(v)) - origin_travel = sum(np.hypot(np.diff(cx), np.diff(cy))) - - if (travel / origin_travel) >= self.invalid_travel_ratio: - print("path is too long") - find_goal = False - - tmp_node = self.Node(x, y, 0) - tmp_node.path_x = x - tmp_node.path_y = y - if not self.check_collision( - tmp_node, self.obstacle_list, self.robot_radius): - print("This path is collision") - find_goal = False - - return find_goal, x, y, yaw, v, t, a, d - - def get_goal_indexes(self): - goalinds = [] - for (i, node) in enumerate(self.node_list): - if self.calc_dist_to_goal(node.x, node.y) <= self.xy_th: - goalinds.append(i) - print("OK XY TH num is") - print(len(goalinds)) - - # angle check - fgoalinds = [] - for i in goalinds: - if abs(self.node_list[i].yaw - self.end.yaw) <= self.yaw_th: - fgoalinds.append(i) - print("OK YAW TH num is") - print(len(fgoalinds)) - - return fgoalinds - - -def main(gx=6.0, gy=7.0, gyaw=np.deg2rad(90.0), max_iter=100): - print("Start" + __file__) - # ====Search Path with RRT==== - obstacle_list = [ - (5, 5, 1), - (4, 6, 1), - (4, 8, 1), - (4, 10, 1), - (6, 5, 1), - (7, 5, 1), - (8, 6, 1), - (8, 8, 1), - (8, 10, 1) - ] # [x,y,size(radius)] - - # Set Initial parameters - start = [0.0, 0.0, np.deg2rad(0.0)] - goal = [gx, gy, gyaw] - - closed_loop_rrt_star = ClosedLoopRRTStar(start, goal, - obstacle_list, - [-2.0, 20.0], - max_iter=max_iter) - flag, x, y, yaw, v, t, a, d = closed_loop_rrt_star.planning( - animation=show_animation) - - if not flag: - print("cannot find feasible path") - - # Draw final path - if show_animation: - closed_loop_rrt_star.draw_graph() - plt.plot(x, y, '-r') - plt.grid(True) - plt.pause(0.001) - - plt.subplots(1) - plt.plot(t, [np.rad2deg(iyaw) for iyaw in yaw[:-1]], '-r') - plt.xlabel("time[s]") - plt.ylabel("Yaw[deg]") - plt.grid(True) - - plt.subplots(1) - plt.plot(t, [iv * 3.6 for iv in v], '-r') - - plt.xlabel("time[s]") - plt.ylabel("velocity[km/h]") - plt.grid(True) - - plt.subplots(1) - plt.plot(t, a, '-r') - plt.xlabel("time[s]") - plt.ylabel("accel[m/ss]") - plt.grid(True) - - plt.subplots(1) - plt.plot(t, [np.rad2deg(td) for td in d], '-r') - plt.xlabel("time[s]") - plt.ylabel("Steering angle[deg]") - plt.grid(True) - - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/ClosedLoopRRTStar/pure_pursuit.py b/PathPlanning/ClosedLoopRRTStar/pure_pursuit.py deleted file mode 100644 index 982ebeca064..00000000000 --- a/PathPlanning/ClosedLoopRRTStar/pure_pursuit.py +++ /dev/null @@ -1,300 +0,0 @@ -""" - -Path tracking simulation with pure pursuit steering control and PID speed control. - -author: Atsushi Sakai - -""" -import math - -import matplotlib.pyplot as plt -import numpy as np - -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from ClosedLoopRRTStar import unicycle_model - -Kp = 2.0 # speed propotional gain -Lf = 0.5 # look-ahead distance -T = 100.0 # max simulation time -goal_dis = 0.5 -stop_speed = 0.5 - -# animation = True -animation = False - - -def PIDControl(target, current): - a = Kp * (target - current) - - if a > unicycle_model.accel_max: - a = unicycle_model.accel_max - elif a < -unicycle_model.accel_max: - a = -unicycle_model.accel_max - - return a - - -def pure_pursuit_control(state, cx, cy, pind): - - ind, dis = calc_target_index(state, cx, cy) - - if pind >= ind: - ind = pind - - # print(parent_index, ind) - if ind < len(cx): - tx = cx[ind] - ty = cy[ind] - else: - tx = cx[-1] - ty = cy[-1] - ind = len(cx) - 1 - - alpha = math.atan2(ty - state.y, tx - state.x) - state.yaw - - if state.v <= 0.0: # back - alpha = math.pi - alpha - - delta = math.atan2(2.0 * unicycle_model.L * math.sin(alpha) / Lf, 1.0) - - if delta > unicycle_model.steer_max: - delta = unicycle_model.steer_max - elif delta < - unicycle_model.steer_max: - delta = -unicycle_model.steer_max - - return delta, ind, dis - - -def calc_target_index(state, cx, cy): - dx = [state.x - icx for icx in cx] - dy = [state.y - icy for icy in cy] - - d = np.hypot(dx, dy) - mindis = min(d) - - ind = np.argmin(d) - - L = 0.0 - - while Lf > L and (ind + 1) < len(cx): - dx = cx[ind + 1] - cx[ind] - dy = cy[ind + 1] - cy[ind] - L += math.hypot(dx, dy) - ind += 1 - - # print(mindis) - return ind, mindis - - -def closed_loop_prediction(cx, cy, cyaw, speed_profile, goal): - - state = unicycle_model.State(x=-0.0, y=-0.0, yaw=0.0, v=0.0) - - # lastIndex = len(cx) - 1 - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - a = [0.0] - d = [0.0] - target_ind, mindis = calc_target_index(state, cx, cy) - find_goal = False - - maxdis = 0.5 - - while T >= time: - di, target_ind, dis = pure_pursuit_control(state, cx, cy, target_ind) - - target_speed = speed_profile[target_ind] - target_speed = target_speed * \ - (maxdis - min(dis, maxdis - 0.1)) / maxdis - - ai = PIDControl(target_speed, state.v) - state = unicycle_model.update(state, ai, di) - - if abs(state.v) <= stop_speed and target_ind <= len(cx) - 2: - target_ind += 1 - - time = time + unicycle_model.dt - - # check goal - dx = state.x - goal[0] - dy = state.y - goal[1] - if math.hypot(dx, dy) <= goal_dis: - find_goal = True - break - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - a.append(ai) - d.append(di) - - if target_ind % 1 == 0 and animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(cx, cy, "-r", label="course") - plt.plot(x, y, "ob", label="trajectory") - plt.plot(cx[target_ind], cy[target_ind], "xg", label="target") - plt.axis("equal") - plt.grid(True) - plt.title("speed:" + str(round(state.v, 2)) - + "tind:" + str(target_ind)) - plt.pause(0.0001) - - else: - print("Time out!!") - - return t, x, y, yaw, v, a, d, find_goal - - -def set_stop_point(target_speed, cx, cy, cyaw): - speed_profile = [target_speed] * len(cx) - forward = True - - d = [] - is_back = False - - # Set stop point - for i in range(len(cx) - 1): - dx = cx[i + 1] - cx[i] - dy = cy[i + 1] - cy[i] - d.append(math.hypot(dx, dy)) - iyaw = cyaw[i] - move_direction = math.atan2(dy, dx) - is_back = abs(move_direction - iyaw) >= math.pi / 2.0 - - if dx == 0.0 and dy == 0.0: - continue - - if is_back: - speed_profile[i] = - target_speed - else: - speed_profile[i] = target_speed - - if is_back and forward: - speed_profile[i] = 0.0 - forward = False - # plt.plot(cx[i], cy[i], "xb") - # print(i_yaw, move_direction, dx, dy) - elif not is_back and not forward: - speed_profile[i] = 0.0 - forward = True - # plt.plot(cx[i], cy[i], "xb") - # print(i_yaw, move_direction, dx, dy) - speed_profile[0] = 0.0 - if is_back: - speed_profile[-1] = -stop_speed - else: - speed_profile[-1] = stop_speed - - d.append(d[-1]) - - return speed_profile, d - - -def calc_speed_profile(cx, cy, cyaw, target_speed): - - speed_profile, d = set_stop_point(target_speed, cx, cy, cyaw) - - if animation: # pragma: no cover - plt.plot(speed_profile, "xb") - - return speed_profile - - -def extend_path(cx, cy, cyaw): - - dl = 0.1 - dl_list = [dl] * (int(Lf / dl) + 1) - - move_direction = math.atan2(cy[-1] - cy[-3], cx[-1] - cx[-3]) - is_back = abs(move_direction - cyaw[-1]) >= math.pi / 2.0 - - for idl in dl_list: - if is_back: - idl *= -1 - cx = np.append(cx, cx[-1] + idl * math.cos(cyaw[-1])) - cy = np.append(cy, cy[-1] + idl * math.sin(cyaw[-1])) - cyaw = np.append(cyaw, cyaw[-1]) - - return cx, cy, cyaw - - -def main(): # pragma: no cover - # target course - cx = np.arange(0, 50, 0.1) - cy = [math.sin(ix / 5.0) * ix / 2.0 for ix in cx] - - target_speed = 5.0 / 3.6 - - T = 15.0 # max simulation time - - state = unicycle_model.State(x=-0.0, y=-3.0, yaw=0.0, v=0.0) - # state = unicycle_model.State(x=-1.0, y=-5.0, yaw=0.0, v=-30.0 / 3.6) - # state = unicycle_model.State(x=10.0, y=5.0, yaw=0.0, v=-30.0 / 3.6) - # state = unicycle_model.State( - # x=3.0, y=5.0, yaw=np.deg2rad(-40.0), v=-10.0 / 3.6) - # state = unicycle_model.State( - # x=3.0, y=5.0, yaw=np.deg2rad(40.0), v=50.0 / 3.6) - - lastIndex = len(cx) - 1 - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - target_ind, dis = calc_target_index(state, cx, cy) - - while T >= time and lastIndex > target_ind: - ai = PIDControl(target_speed, state.v) - di, target_ind, _ = pure_pursuit_control(state, cx, cy, target_ind) - state = unicycle_model.update(state, ai, di) - - time = time + unicycle_model.dt - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - - # plt.cla() - # plt.plot(cx, cy, ".r", label="course") - # plt.plot(x, y, "-b", label="trajectory") - # plt.plot(cx[target_ind], cy[target_ind], "xg", label="target") - # plt.axis("equal") - # plt.grid(True) - # plt.pause(0.1) - # input() - - plt.subplots(1) - plt.plot(cx, cy, ".r", label="course") - plt.plot(x, y, "-b", label="trajectory") - plt.legend() - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.axis("equal") - plt.grid(True) - - plt.subplots(1) - plt.plot(t, [iv * 3.6 for iv in v], "-r") - plt.xlabel("Time[s]") - plt.ylabel("Speed[km/h]") - plt.grid(True) - plt.show() - - -if __name__ == '__main__': # pragma: no cover - print("Pure pursuit path tracking simulation start") - main() diff --git a/PathPlanning/ClosedLoopRRTStar/unicycle_model.py b/PathPlanning/ClosedLoopRRTStar/unicycle_model.py deleted file mode 100644 index c05f76c84e3..00000000000 --- a/PathPlanning/ClosedLoopRRTStar/unicycle_model.py +++ /dev/null @@ -1,80 +0,0 @@ -""" - -Unicycle model class - -author Atsushi Sakai - -""" - -import math -import numpy as np -from utils.angle import angle_mod - -dt = 0.05 # [s] -L = 0.9 # [m] -steer_max = np.deg2rad(40.0) -curvature_max = math.tan(steer_max) / L -curvature_max = 1.0 / curvature_max + 1.0 - -accel_max = 5.0 - - -class State: - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - - -def update(state, a, delta): - - state.x = state.x + state.v * math.cos(state.yaw) * dt - state.y = state.y + state.v * math.sin(state.yaw) * dt - state.yaw = state.yaw + state.v / L * math.tan(delta) * dt - state.yaw = pi_2_pi(state.yaw) - state.v = state.v + a * dt - - return state - - -def pi_2_pi(angle): - return angle_mod(angle) - - -if __name__ == '__main__': # pragma: no cover - print("start unicycle simulation") - import matplotlib.pyplot as plt - - T = 100 - a = [1.0] * T - delta = [np.deg2rad(1.0)] * T - # print(delta) - # print(a, delta) - - state = State() - - x = [] - y = [] - yaw = [] - v = [] - - for (ai, di) in zip(a, delta): - state = update(state, ai, di) - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - - plt.subplots(1) - plt.plot(x, y) - plt.axis("equal") - plt.grid(True) - - plt.subplots(1) - plt.plot(v) - plt.grid(True) - - plt.show() diff --git a/PathPlanning/ClothoidPath/clothoid_path_planner.py b/PathPlanning/ClothoidPath/clothoid_path_planner.py deleted file mode 100644 index 5e5fc6e9a37..00000000000 --- a/PathPlanning/ClothoidPath/clothoid_path_planner.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Clothoid Path Planner -Author: Daniel Ingram (daniel-s-ingram) - Atsushi Sakai (AtsushiSakai) -Reference paper: Fast and accurate G1 fitting of clothoid curves -https://www.researchgate.net/publication/237062806 -""" - -from collections import namedtuple -import matplotlib.pyplot as plt -import numpy as np -import scipy.integrate as integrate -from scipy.optimize import fsolve -from math import atan2, cos, hypot, pi, sin -from matplotlib import animation - -Point = namedtuple("Point", ["x", "y"]) - -show_animation = True - - -def generate_clothoid_paths(start_point, start_yaw_list, - goal_point, goal_yaw_list, - n_path_points): - """ - Generate clothoid path list. This function generate multiple clothoid paths - from multiple orientations(yaw) at start points to multiple orientations - (yaw) at goal point. - - :param start_point: Start point of the path - :param start_yaw_list: Orientation list at start point in radian - :param goal_point: Goal point of the path - :param goal_yaw_list: Orientation list at goal point in radian - :param n_path_points: number of path points - :return: clothoid path list - """ - clothoids = [] - for start_yaw in start_yaw_list: - for goal_yaw in goal_yaw_list: - clothoid = generate_clothoid_path(start_point, start_yaw, - goal_point, goal_yaw, - n_path_points) - clothoids.append(clothoid) - return clothoids - - -def generate_clothoid_path(start_point, start_yaw, - goal_point, goal_yaw, n_path_points): - """ - Generate a clothoid path list. - - :param start_point: Start point of the path - :param start_yaw: Orientation at start point in radian - :param goal_point: Goal point of the path - :param goal_yaw: Orientation at goal point in radian - :param n_path_points: number of path points - :return: a clothoid path - """ - dx = goal_point.x - start_point.x - dy = goal_point.y - start_point.y - r = hypot(dx, dy) - - phi = atan2(dy, dx) - phi1 = normalize_angle(start_yaw - phi) - phi2 = normalize_angle(goal_yaw - phi) - delta = phi2 - phi1 - - try: - # Step1: Solve g function - A = solve_g_for_root(phi1, phi2, delta) - - # Step2: Calculate path parameters - L = compute_path_length(r, phi1, delta, A) - curvature = compute_curvature(delta, A, L) - curvature_rate = compute_curvature_rate(A, L) - except Exception as e: - print(f"Failed to generate clothoid points: {e}") - return None - - # Step3: Construct a path with Fresnel integral - points = [] - for s in np.linspace(0, L, n_path_points): - try: - x = start_point.x + s * X(curvature_rate * s ** 2, curvature * s, - start_yaw) - y = start_point.y + s * Y(curvature_rate * s ** 2, curvature * s, - start_yaw) - points.append(Point(x, y)) - except Exception as e: - print(f"Skipping failed clothoid point: {e}") - - return points - - -def X(a, b, c): - return integrate.quad(lambda t: cos((a/2)*t**2 + b*t + c), 0, 1)[0] - - -def Y(a, b, c): - return integrate.quad(lambda t: sin((a/2)*t**2 + b*t + c), 0, 1)[0] - - -def solve_g_for_root(theta1, theta2, delta): - initial_guess = 3*(theta1 + theta2) - return fsolve(lambda A: Y(2*A, delta - A, theta1), [initial_guess]) - - -def compute_path_length(r, theta1, delta, A): - return r / X(2*A, delta - A, theta1) - - -def compute_curvature(delta, A, L): - return (delta - A) / L - - -def compute_curvature_rate(A, L): - return 2 * A / (L**2) - - -def normalize_angle(angle_rad): - return (angle_rad + pi) % (2 * pi) - pi - - -def get_axes_limits(clothoids): - x_vals = [p.x for clothoid in clothoids for p in clothoid] - y_vals = [p.y for clothoid in clothoids for p in clothoid] - - x_min = min(x_vals) - x_max = max(x_vals) - y_min = min(y_vals) - y_max = max(y_vals) - - x_offset = 0.1*(x_max - x_min) - y_offset = 0.1*(y_max - y_min) - - x_min = x_min - x_offset - x_max = x_max + x_offset - y_min = y_min - y_offset - y_max = y_max + y_offset - - return x_min, x_max, y_min, y_max - - -def draw_clothoids(start, goal, num_steps, clothoidal_paths, - save_animation=False): - - fig = plt.figure(figsize=(10, 10)) - x_min, x_max, y_min, y_max = get_axes_limits(clothoidal_paths) - axes = plt.axes(xlim=(x_min, x_max), ylim=(y_min, y_max)) - - axes.plot(start.x, start.y, 'ro') - axes.plot(goal.x, goal.y, 'ro') - lines = [axes.plot([], [], 'b-')[0] for _ in range(len(clothoidal_paths))] - - def animate(i): - for line, clothoid_path in zip(lines, clothoidal_paths): - x = [p.x for p in clothoid_path[:i]] - y = [p.y for p in clothoid_path[:i]] - line.set_data(x, y) - - return lines - - anim = animation.FuncAnimation( - fig, - animate, - frames=num_steps, - interval=25, - blit=True - ) - if save_animation: - anim.save('clothoid.gif', fps=30, writer="imagemagick") - plt.show() - - -def main(): - start_point = Point(0, 0) - start_orientation_list = [0.0] - goal_point = Point(10, 0) - goal_orientation_list = np.linspace(-pi, pi, 75) - num_path_points = 100 - clothoid_paths = generate_clothoid_paths( - start_point, start_orientation_list, - goal_point, goal_orientation_list, - num_path_points) - if show_animation: - draw_clothoids(start_point, goal_point, - num_path_points, clothoid_paths, - save_animation=False) - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/CubicSpline/__init__.py b/PathPlanning/CubicSpline/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/CubicSpline/cubic_spline_planner.py b/PathPlanning/CubicSpline/cubic_spline_planner.py deleted file mode 100644 index 2391f67c393..00000000000 --- a/PathPlanning/CubicSpline/cubic_spline_planner.py +++ /dev/null @@ -1,455 +0,0 @@ -""" -Cubic spline planner - -Author: Atsushi Sakai(@Atsushi_twi) - -""" -import math -import numpy as np -import bisect - - -class CubicSpline1D: - """ - 1D Cubic Spline class - - Parameters - ---------- - x : list - x coordinates for data points. This x coordinates must be - sorted - in ascending order. - y : list - y coordinates for data points - - Examples - -------- - You can interpolate 1D data points. - - >>> import numpy as np - >>> import matplotlib.pyplot as plt - >>> x = np.arange(5) - >>> y = [1.7, -6, 5, 6.5, 0.0] - >>> sp = CubicSpline1D(x, y) - >>> xi = np.linspace(0.0, 5.0) - >>> yi = [sp.calc_position(x) for x in xi] - >>> plt.plot(x, y, "xb", label="Data points") - >>> plt.plot(xi, yi , "r", label="Cubic spline interpolation") - >>> plt.grid(True) - >>> plt.legend() - >>> plt.show() - - .. image:: cubic_spline_1d.png - - """ - - def __init__(self, x, y): - - h = np.diff(x) - if np.any(h < 0): - raise ValueError("x coordinates must be sorted in ascending order") - - self.a, self.b, self.c, self.d = [], [], [], [] - self.x = x - self.y = y - self.nx = len(x) # dimension of x - - # calc coefficient a - self.a = [iy for iy in y] - - # calc coefficient c - A = self.__calc_A(h) - B = self.__calc_B(h, self.a) - self.c = np.linalg.solve(A, B) - - # calc spline coefficient b and d - for i in range(self.nx - 1): - d = (self.c[i + 1] - self.c[i]) / (3.0 * h[i]) - b = 1.0 / h[i] * (self.a[i + 1] - self.a[i]) \ - - h[i] / 3.0 * (2.0 * self.c[i] + self.c[i + 1]) - self.d.append(d) - self.b.append(b) - - def calc_position(self, x): - """ - Calc `y` position for given `x`. - - if `x` is outside the data point's `x` range, return None. - - Parameters - ---------- - x : float - x position to calculate y. - - Returns - ------- - y : float - y position for given x. - """ - if x < self.x[0]: - return None - elif x > self.x[-1]: - return None - - i = self.__search_index(x) - dx = x - self.x[i] - position = self.a[i] + self.b[i] * dx + \ - self.c[i] * dx ** 2.0 + self.d[i] * dx ** 3.0 - - return position - - def calc_first_derivative(self, x): - """ - Calc first derivative at given x. - - if x is outside the input x, return None - - Parameters - ---------- - x : float - x position to calculate first derivative. - - Returns - ------- - dy : float - first derivative for given x. - """ - - if x < self.x[0]: - return None - elif x > self.x[-1]: - return None - - i = self.__search_index(x) - dx = x - self.x[i] - dy = self.b[i] + 2.0 * self.c[i] * dx + 3.0 * self.d[i] * dx ** 2.0 - return dy - - def calc_second_derivative(self, x): - """ - Calc second derivative at given x. - - if x is outside the input x, return None - - Parameters - ---------- - x : float - x position to calculate second derivative. - - Returns - ------- - ddy : float - second derivative for given x. - """ - - if x < self.x[0]: - return None - elif x > self.x[-1]: - return None - - i = self.__search_index(x) - dx = x - self.x[i] - ddy = 2.0 * self.c[i] + 6.0 * self.d[i] * dx - return ddy - - def calc_third_derivative(self, x): - """ - Calc third derivative at given x. - - if x is outside the input x, return None - - Parameters - ---------- - x : float - x position to calculate third derivative. - - Returns - ------- - dddy : float - third derivative for given x. - """ - if x < self.x[0]: - return None - elif x > self.x[-1]: - return None - - i = self.__search_index(x) - dddy = 6.0 * self.d[i] - return dddy - - def __search_index(self, x): - """ - search data segment index - """ - return bisect.bisect(self.x, x) - 1 - - def __calc_A(self, h): - """ - calc matrix A for spline coefficient c - """ - A = np.zeros((self.nx, self.nx)) - A[0, 0] = 1.0 - for i in range(self.nx - 1): - if i != (self.nx - 2): - A[i + 1, i + 1] = 2.0 * (h[i] + h[i + 1]) - A[i + 1, i] = h[i] - A[i, i + 1] = h[i] - - A[0, 1] = 0.0 - A[self.nx - 1, self.nx - 2] = 0.0 - A[self.nx - 1, self.nx - 1] = 1.0 - return A - - def __calc_B(self, h, a): - """ - calc matrix B for spline coefficient c - """ - B = np.zeros(self.nx) - for i in range(self.nx - 2): - B[i + 1] = 3.0 * (a[i + 2] - a[i + 1]) / h[i + 1]\ - - 3.0 * (a[i + 1] - a[i]) / h[i] - return B - - -class CubicSpline2D: - """ - Cubic CubicSpline2D class - - Parameters - ---------- - x : list - x coordinates for data points. - y : list - y coordinates for data points. - - Examples - -------- - You can interpolate a 2D data points. - - >>> import matplotlib.pyplot as plt - >>> x = [-2.5, 0.0, 2.5, 5.0, 7.5, 3.0, -1.0] - >>> y = [0.7, -6, 5, 6.5, 0.0, 5.0, -2.0] - >>> ds = 0.1 # [m] distance of each interpolated points - >>> sp = CubicSpline2D(x, y) - >>> s = np.arange(0, sp.s[-1], ds) - >>> rx, ry, ryaw, rk = [], [], [], [] - >>> for i_s in s: - ... ix, iy = sp.calc_position(i_s) - ... rx.append(ix) - ... ry.append(iy) - ... ryaw.append(sp.calc_yaw(i_s)) - ... rk.append(sp.calc_curvature(i_s)) - >>> plt.subplots(1) - >>> plt.plot(x, y, "xb", label="Data points") - >>> plt.plot(rx, ry, "-r", label="Cubic spline path") - >>> plt.grid(True) - >>> plt.axis("equal") - >>> plt.xlabel("x[m]") - >>> plt.ylabel("y[m]") - >>> plt.legend() - >>> plt.show() - - .. image:: cubic_spline_2d_path.png - - >>> plt.subplots(1) - >>> plt.plot(s, [np.rad2deg(iyaw) for iyaw in ryaw], "-r", label="yaw") - >>> plt.grid(True) - >>> plt.legend() - >>> plt.xlabel("line length[m]") - >>> plt.ylabel("yaw angle[deg]") - - .. image:: cubic_spline_2d_yaw.png - - >>> plt.subplots(1) - >>> plt.plot(s, rk, "-r", label="curvature") - >>> plt.grid(True) - >>> plt.legend() - >>> plt.xlabel("line length[m]") - >>> plt.ylabel("curvature [1/m]") - - .. image:: cubic_spline_2d_curvature.png - """ - - def __init__(self, x, y): - self.s = self.__calc_s(x, y) - self.sx = CubicSpline1D(self.s, x) - self.sy = CubicSpline1D(self.s, y) - - def __calc_s(self, x, y): - dx = np.diff(x) - dy = np.diff(y) - self.ds = np.hypot(dx, dy) - s = [0] - s.extend(np.cumsum(self.ds)) - return s - - def calc_position(self, s): - """ - calc position - - Parameters - ---------- - s : float - distance from the start point. if `s` is outside the data point's - range, return None. - - Returns - ------- - x : float - x position for given s. - y : float - y position for given s. - """ - x = self.sx.calc_position(s) - y = self.sy.calc_position(s) - - return x, y - - def calc_curvature(self, s): - """ - calc curvature - - Parameters - ---------- - s : float - distance from the start point. if `s` is outside the data point's - range, return None. - - Returns - ------- - k : float - curvature for given s. - """ - dx = self.sx.calc_first_derivative(s) - ddx = self.sx.calc_second_derivative(s) - dy = self.sy.calc_first_derivative(s) - ddy = self.sy.calc_second_derivative(s) - k = (ddy * dx - ddx * dy) / ((dx ** 2 + dy ** 2)**(3 / 2)) - return k - - def calc_curvature_rate(self, s): - """ - calc curvature rate - - Parameters - ---------- - s : float - distance from the start point. if `s` is outside the data point's - range, return None. - - Returns - ------- - k : float - curvature rate for given s. - """ - dx = self.sx.calc_first_derivative(s) - dy = self.sy.calc_first_derivative(s) - ddx = self.sx.calc_second_derivative(s) - ddy = self.sy.calc_second_derivative(s) - dddx = self.sx.calc_third_derivative(s) - dddy = self.sy.calc_third_derivative(s) - a = dx * ddy - dy * ddx - b = dx * dddy - dy * dddx - c = dx * ddx + dy * ddy - d = dx * dx + dy * dy - return (b * d - 3.0 * a * c) / (d * d * d) - - def calc_yaw(self, s): - """ - calc yaw - - Parameters - ---------- - s : float - distance from the start point. if `s` is outside the data point's - range, return None. - - Returns - ------- - yaw : float - yaw angle (tangent vector) for given s. - """ - dx = self.sx.calc_first_derivative(s) - dy = self.sy.calc_first_derivative(s) - yaw = math.atan2(dy, dx) - return yaw - - -def calc_spline_course(x, y, ds=0.1): - sp = CubicSpline2D(x, y) - s = list(np.arange(0, sp.s[-1], ds)) - - rx, ry, ryaw, rk = [], [], [], [] - for i_s in s: - ix, iy = sp.calc_position(i_s) - rx.append(ix) - ry.append(iy) - ryaw.append(sp.calc_yaw(i_s)) - rk.append(sp.calc_curvature(i_s)) - - return rx, ry, ryaw, rk, s - - -def main_1d(): - print("CubicSpline1D test") - import matplotlib.pyplot as plt - x = np.arange(5) - y = [1.7, -6, 5, 6.5, 0.0] - sp = CubicSpline1D(x, y) - xi = np.linspace(0.0, 5.0) - - plt.plot(x, y, "xb", label="Data points") - plt.plot(xi, [sp.calc_position(x) for x in xi], "r", - label="Cubic spline interpolation") - plt.grid(True) - plt.legend() - plt.show() - - -def main_2d(): # pragma: no cover - print("CubicSpline1D 2D test") - import matplotlib.pyplot as plt - x = [-2.5, 0.0, 2.5, 5.0, 7.5, 3.0, -1.0] - y = [0.7, -6, 5, 6.5, 0.0, 5.0, -2.0] - ds = 0.1 # [m] distance of each interpolated points - - sp = CubicSpline2D(x, y) - s = np.arange(0, sp.s[-1], ds) - - rx, ry, ryaw, rk = [], [], [], [] - for i_s in s: - ix, iy = sp.calc_position(i_s) - rx.append(ix) - ry.append(iy) - ryaw.append(sp.calc_yaw(i_s)) - rk.append(sp.calc_curvature(i_s)) - - plt.subplots(1) - plt.plot(x, y, "xb", label="Data points") - plt.plot(rx, ry, "-r", label="Cubic spline path") - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - - plt.subplots(1) - plt.plot(s, [np.rad2deg(iyaw) for iyaw in ryaw], "-r", label="yaw") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("yaw angle[deg]") - - plt.subplots(1) - plt.plot(s, rk, "-r", label="curvature") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("curvature [1/m]") - - plt.show() - - -if __name__ == '__main__': - # main_1d() - main_2d() diff --git a/PathPlanning/CubicSpline/spline_continuity.py b/PathPlanning/CubicSpline/spline_continuity.py deleted file mode 100644 index ea85b37f7ce..00000000000 --- a/PathPlanning/CubicSpline/spline_continuity.py +++ /dev/null @@ -1,55 +0,0 @@ - -import numpy as np -import matplotlib.pyplot as plt -from scipy import interpolate - - -class Spline2D: - - def __init__(self, x, y, kind="cubic"): - self.s = self.__calc_s(x, y) - self.sx = interpolate.interp1d(self.s, x, kind=kind) - self.sy = interpolate.interp1d(self.s, y, kind=kind) - - def __calc_s(self, x, y): - self.ds = np.hypot(np.diff(x), np.diff(y)) - s = [0.0] - s.extend(np.cumsum(self.ds)) - return s - - def calc_position(self, s): - x = self.sx(s) - y = self.sy(s) - return x, y - - -def main(): - x = [-2.5, 0.0, 2.5, 5.0, 7.5, 3.0, -1.0] - y = [0.7, -6, -5, -3.5, 0.0, 5.0, -2.0] - ds = 0.1 # [m] distance of each interpolated points - - plt.subplots(1) - plt.plot(x, y, "xb", label="Data points") - - for (kind, label) in [("linear", "C0 (Linear spline)"), - ("quadratic", "C0 & C1 (Quadratic spline)"), - ("cubic", "C0 & C1 & C2 (Cubic spline)")]: - rx, ry = [], [] - sp = Spline2D(x, y, kind=kind) - s = np.arange(0, sp.s[-1], ds) - for i_s in s: - ix, iy = sp.calc_position(i_s) - rx.append(ix) - ry.append(iy) - plt.plot(rx, ry, "-", label=label) - - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/DStar/dstar.py b/PathPlanning/DStar/dstar.py deleted file mode 100644 index b62b939f542..00000000000 --- a/PathPlanning/DStar/dstar.py +++ /dev/null @@ -1,253 +0,0 @@ -""" - -D* grid planning - -author: Nirnay Roy - -See Wikipedia article (https://en.wikipedia.org/wiki/D*) - -""" -import math - - -from sys import maxsize - -import matplotlib.pyplot as plt - -show_animation = True - - -class State: - - def __init__(self, x, y): - self.x = x - self.y = y - self.parent = None - self.state = "." - self.t = "new" # tag for state - self.h = 0 - self.k = 0 - - def cost(self, state): - if self.state == "#" or state.state == "#": - return maxsize - - return math.sqrt(math.pow((self.x - state.x), 2) + - math.pow((self.y - state.y), 2)) - - def set_state(self, state): - """ - .: new - #: obstacle - e: oparent of current state - *: closed state - s: current state - """ - if state not in ["s", ".", "#", "e", "*"]: - return - self.state = state - - -class Map: - - def __init__(self, row, col): - self.row = row - self.col = col - self.map = self.init_map() - - def init_map(self): - map_list = [] - for i in range(self.row): - tmp = [] - for j in range(self.col): - tmp.append(State(i, j)) - map_list.append(tmp) - return map_list - - def get_neighbors(self, state): - state_list = [] - for i in [-1, 0, 1]: - for j in [-1, 0, 1]: - if i == 0 and j == 0: - continue - if state.x + i < 0 or state.x + i >= self.row: - continue - if state.y + j < 0 or state.y + j >= self.col: - continue - state_list.append(self.map[state.x + i][state.y + j]) - return state_list - - def set_obstacle(self, point_list): - for x, y in point_list: - if x < 0 or x >= self.row or y < 0 or y >= self.col: - continue - - self.map[x][y].set_state("#") - - -class Dstar: - def __init__(self, maps): - self.map = maps - self.open_list = set() - - def process_state(self): - x = self.min_state() - - if x is None: - return -1 - - k_old = self.get_kmin() - self.remove(x) - - if k_old < x.h: - for y in self.map.get_neighbors(x): - if y.h <= k_old and x.h > y.h + x.cost(y): - x.parent = y - x.h = y.h + x.cost(y) - if k_old == x.h: - for y in self.map.get_neighbors(x): - if y.t == "new" or y.parent == x and y.h != x.h + x.cost(y) \ - or y.parent != x and y.h > x.h + x.cost(y): - y.parent = x - self.insert(y, x.h + x.cost(y)) - else: - for y in self.map.get_neighbors(x): - if y.t == "new" or y.parent == x and y.h != x.h + x.cost(y): - y.parent = x - self.insert(y, x.h + x.cost(y)) - else: - if y.parent != x and y.h > x.h + x.cost(y): - self.insert(x, x.h) - else: - if y.parent != x and x.h > y.h + x.cost(y) \ - and y.t == "close" and y.h > k_old: - self.insert(y, y.h) - return self.get_kmin() - - def min_state(self): - if not self.open_list: - return None - min_state = min(self.open_list, key=lambda x: x.k) - return min_state - - def get_kmin(self): - if not self.open_list: - return -1 - k_min = min([x.k for x in self.open_list]) - return k_min - - def insert(self, state, h_new): - if state.t == "new": - state.k = h_new - elif state.t == "open": - state.k = min(state.k, h_new) - elif state.t == "close": - state.k = min(state.h, h_new) - state.h = h_new - state.t = "open" - self.open_list.add(state) - - def remove(self, state): - if state.t == "open": - state.t = "close" - self.open_list.remove(state) - - def modify_cost(self, x): - if x.t == "close": - self.insert(x, x.parent.h + x.cost(x.parent)) - - def run(self, start, end): - - rx = [] - ry = [] - - self.insert(end, 0.0) - - while True: - self.process_state() - if start.t == "close": - break - - start.set_state("s") - s = start - s = s.parent - s.set_state("e") - tmp = start - - AddNewObstacle(self.map) # add new obstacle after the first search finished - - while tmp != end: - tmp.set_state("*") - rx.append(tmp.x) - ry.append(tmp.y) - if show_animation: - plt.plot(rx, ry, "-r") - plt.pause(0.01) - if tmp.parent.state == "#": - self.modify(tmp) - continue - tmp = tmp.parent - tmp.set_state("e") - - return rx, ry - - def modify(self, state): - self.modify_cost(state) - while True: - k_min = self.process_state() - if k_min >= state.h: - break - -def AddNewObstacle(map:Map): - ox, oy = [], [] - for i in range(5, 21): - ox.append(i) - oy.append(40) - map.set_obstacle([(i, j) for i, j in zip(ox, oy)]) - if show_animation: - plt.pause(0.001) - plt.plot(ox, oy, ".g") - -def main(): - m = Map(100, 100) - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10) - for i in range(-10, 60): - ox.append(60) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60) - for i in range(-10, 61): - ox.append(-10) - oy.append(i) - for i in range(-10, 40): - ox.append(20) - oy.append(i) - for i in range(0, 40): - ox.append(40) - oy.append(60 - i) - m.set_obstacle([(i, j) for i, j in zip(ox, oy)]) - - start = [10, 10] - goal = [50, 50] - if show_animation: - plt.plot(ox, oy, ".k") - plt.plot(start[0], start[1], "og") - plt.plot(goal[0], goal[1], "xb") - plt.axis("equal") - - start = m.map[start[0]][start[1]] - end = m.map[goal[0]][goal[1]] - dstar = Dstar(m) - rx, ry = dstar.run(start, end) - - if show_animation: - plt.plot(rx, ry, "-r") - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/DStarLite/d_star_lite.py b/PathPlanning/DStarLite/d_star_lite.py deleted file mode 100644 index f099530173f..00000000000 --- a/PathPlanning/DStarLite/d_star_lite.py +++ /dev/null @@ -1,427 +0,0 @@ -""" -D* Lite grid planning -author: vss2sn (28676655+vss2sn@users.noreply.github.com) -Link to papers: -D* Lite (Link: http://idm-lab.org/bib/abstracts/papers/aaai02b.pdf) -Improved Fast Replanning for Robot Navigation in Unknown Terrain -(Link: http://www.cs.cmu.edu/~maxim/files/dlite_icra02.pdf) -Implemented maintaining similarity with the pseudocode for understanding. -Code can be significantly optimized by using a priority queue for U, etc. -Avoiding additional imports based on repository philosophy. -""" -import math -import matplotlib.pyplot as plt -import random -import numpy as np - -show_animation = True -pause_time = 0.001 -p_create_random_obstacle = 0 - - -class Node: - def __init__(self, x: int = 0, y: int = 0, cost: float = 0.0): - self.x = x - self.y = y - self.cost = cost - - -def add_coordinates(node1: Node, node2: Node): - new_node = Node() - new_node.x = node1.x + node2.x - new_node.y = node1.y + node2.y - new_node.cost = node1.cost + node2.cost - return new_node - - -def compare_coordinates(node1: Node, node2: Node): - return node1.x == node2.x and node1.y == node2.y - - -class DStarLite: - - # Please adjust the heuristic function (h) if you change the list of - # possible motions - motions = [ - Node(1, 0, 1), - Node(0, 1, 1), - Node(-1, 0, 1), - Node(0, -1, 1), - Node(1, 1, math.sqrt(2)), - Node(1, -1, math.sqrt(2)), - Node(-1, 1, math.sqrt(2)), - Node(-1, -1, math.sqrt(2)) - ] - - def __init__(self, ox: list, oy: list): - # Ensure that within the algorithm implementation all node coordinates - # are indices in the grid and extend - # from 0 to abs(<axis>_max - <axis>_min) - self.x_min_world = int(min(ox)) - self.y_min_world = int(min(oy)) - self.x_max = int(abs(max(ox) - self.x_min_world)) - self.y_max = int(abs(max(oy) - self.y_min_world)) - self.obstacles = [Node(x - self.x_min_world, y - self.y_min_world) - for x, y in zip(ox, oy)] - self.obstacles_xy = np.array( - [[obstacle.x, obstacle.y] for obstacle in self.obstacles] - ) - self.start = Node(0, 0) - self.goal = Node(0, 0) - self.U = list() # type: ignore - self.km = 0.0 - self.kold = 0.0 - self.rhs = self.create_grid(float("inf")) - self.g = self.create_grid(float("inf")) - self.detected_obstacles_xy = np.empty((0, 2)) - self.xy = np.empty((0, 2)) - if show_animation: - self.detected_obstacles_for_plotting_x = list() # type: ignore - self.detected_obstacles_for_plotting_y = list() # type: ignore - self.initialized = False - - def create_grid(self, val: float): - return np.full((self.x_max, self.y_max), val) - - def is_obstacle(self, node: Node): - x = np.array([node.x]) - y = np.array([node.y]) - obstacle_x_equal = self.obstacles_xy[:, 0] == x - obstacle_y_equal = self.obstacles_xy[:, 1] == y - is_in_obstacles = (obstacle_x_equal & obstacle_y_equal).any() - - is_in_detected_obstacles = False - if self.detected_obstacles_xy.shape[0] > 0: - is_x_equal = self.detected_obstacles_xy[:, 0] == x - is_y_equal = self.detected_obstacles_xy[:, 1] == y - is_in_detected_obstacles = (is_x_equal & is_y_equal).any() - - return is_in_obstacles or is_in_detected_obstacles - - def c(self, node1: Node, node2: Node): - if self.is_obstacle(node2): - # Attempting to move from or to an obstacle - return math.inf - new_node = Node(node1.x-node2.x, node1.y-node2.y) - detected_motion = list(filter(lambda motion: - compare_coordinates(motion, new_node), - self.motions)) - return detected_motion[0].cost - - def h(self, s: Node): - # Cannot use the 2nd euclidean norm as this might sometimes generate - # heuristics that overestimate the cost, making them inadmissible, - # due to rounding errors etc (when combined with calculate_key) - # To be admissible heuristic should - # never overestimate the cost of a move - # hence not using the line below - # return math.hypot(self.start.x - s.x, self.start.y - s.y) - - # Below is the same as 1; modify if you modify the cost of each move in - # motion - # return max(abs(self.start.x - s.x), abs(self.start.y - s.y)) - return 1 - - def calculate_key(self, s: Node): - return (min(self.g[s.x][s.y], self.rhs[s.x][s.y]) + self.h(s) - + self.km, min(self.g[s.x][s.y], self.rhs[s.x][s.y])) - - def is_valid(self, node: Node): - if 0 <= node.x < self.x_max and 0 <= node.y < self.y_max: - return True - return False - - def get_neighbours(self, u: Node): - return [add_coordinates(u, motion) for motion in self.motions - if self.is_valid(add_coordinates(u, motion))] - - def pred(self, u: Node): - # Grid, so each vertex is connected to the ones around it - return self.get_neighbours(u) - - def succ(self, u: Node): - # Grid, so each vertex is connected to the ones around it - return self.get_neighbours(u) - - def initialize(self, start: Node, goal: Node): - self.start.x = start.x - self.x_min_world - self.start.y = start.y - self.y_min_world - self.goal.x = goal.x - self.x_min_world - self.goal.y = goal.y - self.y_min_world - if not self.initialized: - self.initialized = True - print('Initializing') - self.U = list() # Would normally be a priority queue - self.km = 0.0 - self.rhs = self.create_grid(math.inf) - self.g = self.create_grid(math.inf) - self.rhs[self.goal.x][self.goal.y] = 0 - self.U.append((self.goal, self.calculate_key(self.goal))) - self.detected_obstacles_xy = np.empty((0, 2)) - - def update_vertex(self, u: Node): - if not compare_coordinates(u, self.goal): - self.rhs[u.x][u.y] = min([self.c(u, sprime) + - self.g[sprime.x][sprime.y] - for sprime in self.succ(u)]) - if any([compare_coordinates(u, node) for node, key in self.U]): - self.U = [(node, key) for node, key in self.U - if not compare_coordinates(node, u)] - self.U.sort(key=lambda x: x[1]) - if self.g[u.x][u.y] != self.rhs[u.x][u.y]: - self.U.append((u, self.calculate_key(u))) - self.U.sort(key=lambda x: x[1]) - - def compare_keys(self, key_pair1: tuple[float, float], - key_pair2: tuple[float, float]): - return key_pair1[0] < key_pair2[0] or \ - (key_pair1[0] == key_pair2[0] and key_pair1[1] < key_pair2[1]) - - def compute_shortest_path(self): - self.U.sort(key=lambda x: x[1]) - has_elements = len(self.U) > 0 - start_key_not_updated = self.compare_keys( - self.U[0][1], self.calculate_key(self.start) - ) - rhs_not_equal_to_g = self.rhs[self.start.x][self.start.y] != \ - self.g[self.start.x][self.start.y] - while has_elements and start_key_not_updated or rhs_not_equal_to_g: - self.kold = self.U[0][1] - u = self.U[0][0] - self.U.pop(0) - if self.compare_keys(self.kold, self.calculate_key(u)): - self.U.append((u, self.calculate_key(u))) - self.U.sort(key=lambda x: x[1]) - elif (self.g[u.x, u.y] > self.rhs[u.x, u.y]).any(): - self.g[u.x, u.y] = self.rhs[u.x, u.y] - for s in self.pred(u): - self.update_vertex(s) - else: - self.g[u.x, u.y] = math.inf - for s in self.pred(u) + [u]: - self.update_vertex(s) - self.U.sort(key=lambda x: x[1]) - start_key_not_updated = self.compare_keys( - self.U[0][1], self.calculate_key(self.start) - ) - rhs_not_equal_to_g = self.rhs[self.start.x][self.start.y] != \ - self.g[self.start.x][self.start.y] - - def detect_changes(self): - changed_vertices = list() - if len(self.spoofed_obstacles) > 0: - for spoofed_obstacle in self.spoofed_obstacles[0]: - if compare_coordinates(spoofed_obstacle, self.start) or \ - compare_coordinates(spoofed_obstacle, self.goal): - continue - changed_vertices.append(spoofed_obstacle) - self.detected_obstacles_xy = np.concatenate( - ( - self.detected_obstacles_xy, - [[spoofed_obstacle.x, spoofed_obstacle.y]] - ) - ) - if show_animation: - self.detected_obstacles_for_plotting_x.append( - spoofed_obstacle.x + self.x_min_world) - self.detected_obstacles_for_plotting_y.append( - spoofed_obstacle.y + self.y_min_world) - plt.plot(self.detected_obstacles_for_plotting_x, - self.detected_obstacles_for_plotting_y, ".k") - plt.pause(pause_time) - self.spoofed_obstacles.pop(0) - - # Allows random generation of obstacles - random.seed() - if random.random() > 1 - p_create_random_obstacle: - x = random.randint(0, self.x_max - 1) - y = random.randint(0, self.y_max - 1) - new_obs = Node(x, y) - if compare_coordinates(new_obs, self.start) or \ - compare_coordinates(new_obs, self.goal): - return changed_vertices - changed_vertices.append(Node(x, y)) - self.detected_obstacles_xy = np.concatenate( - ( - self.detected_obstacles_xy, - [[x, y]] - ) - ) - if show_animation: - self.detected_obstacles_for_plotting_x.append(x + - self.x_min_world) - self.detected_obstacles_for_plotting_y.append(y + - self.y_min_world) - plt.plot(self.detected_obstacles_for_plotting_x, - self.detected_obstacles_for_plotting_y, ".k") - plt.pause(pause_time) - return changed_vertices - - def compute_current_path(self): - path = list() - current_point = Node(self.start.x, self.start.y) - while not compare_coordinates(current_point, self.goal): - path.append(current_point) - current_point = min(self.succ(current_point), - key=lambda sprime: - self.c(current_point, sprime) + - self.g[sprime.x][sprime.y]) - path.append(self.goal) - return path - - def compare_paths(self, path1: list, path2: list): - if len(path1) != len(path2): - return False - for node1, node2 in zip(path1, path2): - if not compare_coordinates(node1, node2): - return False - return True - - def display_path(self, path: list, colour: str, alpha: float = 1.0): - px = [(node.x + self.x_min_world) for node in path] - py = [(node.y + self.y_min_world) for node in path] - drawing = plt.plot(px, py, colour, alpha=alpha) - plt.pause(pause_time) - return drawing - - def main(self, start: Node, goal: Node, - spoofed_ox: list, spoofed_oy: list): - self.spoofed_obstacles = [[Node(x - self.x_min_world, - y - self.y_min_world) - for x, y in zip(rowx, rowy)] - for rowx, rowy in zip(spoofed_ox, spoofed_oy) - ] - pathx = [] - pathy = [] - self.initialize(start, goal) - last = self.start - self.compute_shortest_path() - pathx.append(self.start.x + self.x_min_world) - pathy.append(self.start.y + self.y_min_world) - - if show_animation: - current_path = self.compute_current_path() - previous_path = current_path.copy() - previous_path_image = self.display_path(previous_path, ".c", - alpha=0.3) - current_path_image = self.display_path(current_path, ".c") - - while not compare_coordinates(self.goal, self.start): - if self.g[self.start.x][self.start.y] == math.inf: - print("No path possible") - return False, pathx, pathy - self.start = min(self.succ(self.start), - key=lambda sprime: - self.c(self.start, sprime) + - self.g[sprime.x][sprime.y]) - pathx.append(self.start.x + self.x_min_world) - pathy.append(self.start.y + self.y_min_world) - if show_animation: - current_path.pop(0) - plt.plot(pathx, pathy, "-r") - plt.pause(pause_time) - changed_vertices = self.detect_changes() - if len(changed_vertices) != 0: - print("New obstacle detected") - self.km += self.h(last) - last = self.start - for u in changed_vertices: - if compare_coordinates(u, self.start): - continue - self.rhs[u.x][u.y] = math.inf - self.g[u.x][u.y] = math.inf - self.update_vertex(u) - self.compute_shortest_path() - - if show_animation: - new_path = self.compute_current_path() - if not self.compare_paths(current_path, new_path): - current_path_image[0].remove() - previous_path_image[0].remove() - previous_path = current_path.copy() - current_path = new_path.copy() - previous_path_image = self.display_path(previous_path, - ".c", - alpha=0.3) - current_path_image = self.display_path(current_path, - ".c") - plt.pause(pause_time) - print("Path found") - return True, pathx, pathy - - -def main(): - - # start and goal position - sx = 10 # [m] - sy = 10 # [m] - gx = 50 # [m] - gy = 50 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(i) - for i in range(-10, 40): - ox.append(20.0) - oy.append(i) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "xb") - plt.grid(True) - plt.axis("equal") - label_column = ['Start', 'Goal', 'Path taken', - 'Current computed path', 'Previous computed path', - 'Obstacles'] - columns = [plt.plot([], [], symbol, color=colour, alpha=alpha)[0] - for symbol, colour, alpha in [['o', 'g', 1], - ['x', 'b', 1], - ['-', 'r', 1], - ['.', 'c', 1], - ['.', 'c', 0.3], - ['.', 'k', 1]]] - plt.legend(columns, label_column, bbox_to_anchor=(1, 1), title="Key:", - fontsize="xx-small") - plt.plot() - plt.pause(pause_time) - - # Obstacles discovered at time = row - # time = 1, obstacles discovered at (0, 2), (9, 2), (4, 0) - # time = 2, obstacles discovered at (0, 1), (7, 7) - # ... - # when the spoofed obstacles are: - # spoofed_ox = [[0, 9, 4], [0, 7], [], [], [], [], [], [5]] - # spoofed_oy = [[2, 2, 0], [1, 7], [], [], [], [], [], [4]] - - # Reroute - # spoofed_ox = [[], [], [], [], [], [], [], [40 for _ in range(10, 21)]] - # spoofed_oy = [[], [], [], [], [], [], [], [i for i in range(10, 21)]] - - # Obstacles that demostrate large rerouting - spoofed_ox = [[], [], [], - [i for i in range(0, 21)] + [0 for _ in range(0, 20)]] - spoofed_oy = [[], [], [], - [20 for _ in range(0, 21)] + [i for i in range(0, 20)]] - - dstarlite = DStarLite(ox, oy) - dstarlite.main(Node(x=sx, y=sy), Node(x=gx, y=gy), - spoofed_ox=spoofed_ox, spoofed_oy=spoofed_oy) - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/DepthFirstSearch/depth_first_search.py b/PathPlanning/DepthFirstSearch/depth_first_search.py deleted file mode 100644 index 6922b8cbadc..00000000000 --- a/PathPlanning/DepthFirstSearch/depth_first_search.py +++ /dev/null @@ -1,255 +0,0 @@ -""" - -Depth-First grid planning - -author: Erwin Lejeune (@spida_rwin) - -See Wikipedia article (https://en.wikipedia.org/wiki/Depth-first_search) - -""" - -import math - -import matplotlib.pyplot as plt - -show_animation = True - - -class DepthFirstSearchPlanner: - - def __init__(self, ox, oy, reso, rr): - """ - Initialize grid map for Depth-First planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.reso = reso - self.rr = rr - self.calc_obstacle_map(ox, oy) - self.motion = self.get_motion_model() - - class Node: - def __init__(self, x, y, cost, parent_index, parent): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index - self.parent = parent - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, sx, sy, gx, gy): - """ - Depth First search - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gy: goal y position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - nstart = self.Node(self.calc_xyindex(sx, self.minx), - self.calc_xyindex(sy, self.miny), 0.0, -1, None) - ngoal = self.Node(self.calc_xyindex(gx, self.minx), - self.calc_xyindex(gy, self.miny), 0.0, -1, None) - - open_set, closed_set = dict(), dict() - open_set[self.calc_grid_index(nstart)] = nstart - - while True: - if len(open_set) == 0: - print("Open set is empty..") - break - - current = open_set.pop(list(open_set.keys())[-1]) - c_id = self.calc_grid_index(current) - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_grid_position(current.x, self.minx), - self.calc_grid_position(current.y, self.miny), "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: - [exit(0) if event.key == 'escape' - else None]) - plt.pause(0.01) - - if current.x == ngoal.x and current.y == ngoal.y: - print("Find goal") - ngoal.parent_index = current.parent_index - ngoal.cost = current.cost - break - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - node = self.Node(current.x + self.motion[i][0], - current.y + self.motion[i][1], - current.cost + self.motion[i][2], c_id, None) - n_id = self.calc_grid_index(node) - - # If the node is not safe, do nothing - if not self.verify_node(node): - continue - - if n_id not in closed_set: - open_set[n_id] = node - closed_set[n_id] = node - node.parent = current - - rx, ry = self.calc_final_path(ngoal, closed_set) - return rx, ry - - def calc_final_path(self, ngoal, closedset): - # generate final course - rx, ry = [self.calc_grid_position(ngoal.x, self.minx)], [ - self.calc_grid_position(ngoal.y, self.miny)] - n = closedset[ngoal.parent_index] - while n is not None: - rx.append(self.calc_grid_position(n.x, self.minx)) - ry.append(self.calc_grid_position(n.y, self.miny)) - n = n.parent - - return rx, ry - - def calc_grid_position(self, index, minp): - """ - calc grid position - - :param index: - :param minp: - :return: - """ - pos = index * self.reso + minp - return pos - - def calc_xyindex(self, position, min_pos): - return round((position - min_pos) / self.reso) - - def calc_grid_index(self, node): - return (node.y - self.miny) * self.xwidth + (node.x - self.minx) - - def verify_node(self, node): - px = self.calc_grid_position(node.x, self.minx) - py = self.calc_grid_position(node.y, self.miny) - - if px < self.minx: - return False - elif py < self.miny: - return False - elif px >= self.maxx: - return False - elif py >= self.maxy: - return False - - # collision check - if self.obmap[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.minx = round(min(ox)) - self.miny = round(min(oy)) - self.maxx = round(max(ox)) - self.maxy = round(max(oy)) - print("min_x:", self.minx) - print("min_y:", self.miny) - print("max_x:", self.maxx) - print("max_y:", self.maxy) - - self.xwidth = round((self.maxx - self.minx) / self.reso) - self.ywidth = round((self.maxy - self.miny) / self.reso) - print("x_width:", self.xwidth) - print("y_width:", self.ywidth) - - # obstacle map generation - self.obmap = [[False for _ in range(self.ywidth)] - for _ in range(self.xwidth)] - for ix in range(self.xwidth): - x = self.calc_grid_position(ix, self.minx) - for iy in range(self.ywidth): - y = self.calc_grid_position(iy, self.miny) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.rr: - self.obmap[ix][iy] = True - break - - @staticmethod - 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 - - -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 = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(i) - for i in range(-10, 40): - ox.append(20.0) - oy.append(i) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "xb") - plt.grid(True) - plt.axis("equal") - - dfs = DepthFirstSearchPlanner(ox, oy, grid_size, robot_radius) - rx, ry = dfs.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.01) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/Dijkstra/dijkstra.py b/PathPlanning/Dijkstra/dijkstra.py deleted file mode 100644 index 8a585e4b182..00000000000 --- a/PathPlanning/Dijkstra/dijkstra.py +++ /dev/null @@ -1,259 +0,0 @@ -""" - -Grid based Dijkstra planning - -author: Atsushi Sakai(@Atsushi_twi) - -""" - -import matplotlib.pyplot as plt -import math - -show_animation = True - - -class Dijkstra: - - def __init__(self, ox, oy, resolution, robot_radius): - """ - Initialize map for a star planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.min_x = None - self.min_y = None - self.max_x = None - self.max_y = None - self.x_width = None - self.y_width = None - self.obstacle_map = None - - self.resolution = resolution - self.robot_radius = robot_radius - self.calc_obstacle_map(ox, oy) - self.motion = self.get_motion_model() - - class Node: - def __init__(self, x, y, cost, parent_index): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index # index of previous Node - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, sx, sy, gx, gy): - """ - dijkstra path search - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gx: goal x position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - start_node = self.Node(self.calc_xy_index(sx, self.min_x), - self.calc_xy_index(sy, self.min_y), 0.0, -1) - goal_node = self.Node(self.calc_xy_index(gx, self.min_x), - self.calc_xy_index(gy, self.min_y), 0.0, -1) - - open_set, closed_set = dict(), dict() - open_set[self.calc_index(start_node)] = start_node - - while True: - c_id = min(open_set, key=lambda o: open_set[o].cost) - current = open_set[c_id] - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_position(current.x, self.min_x), - self.calc_position(current.y, self.min_y), "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if len(closed_set.keys()) % 10 == 0: - plt.pause(0.001) - - if current.x == goal_node.x and current.y == goal_node.y: - print("Find goal") - goal_node.parent_index = current.parent_index - goal_node.cost = current.cost - break - - # Remove the item from the open set - del open_set[c_id] - - # Add it to the closed set - closed_set[c_id] = current - - # expand search grid based on motion model - for move_x, move_y, move_cost in self.motion: - node = self.Node(current.x + move_x, - current.y + move_y, - current.cost + move_cost, c_id) - n_id = self.calc_index(node) - - if n_id in closed_set: - continue - - if not self.verify_node(node): - continue - - if n_id not in open_set: - open_set[n_id] = node # Discover a new node - else: - if open_set[n_id].cost >= node.cost: - # This path is the best until now. record it! - open_set[n_id] = node - - rx, ry = self.calc_final_path(goal_node, closed_set) - - return rx, ry - - def calc_final_path(self, goal_node, closed_set): - # generate final course - rx, ry = [self.calc_position(goal_node.x, self.min_x)], [ - self.calc_position(goal_node.y, self.min_y)] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_set[parent_index] - rx.append(self.calc_position(n.x, self.min_x)) - ry.append(self.calc_position(n.y, self.min_y)) - parent_index = n.parent_index - - return rx, ry - - def calc_position(self, index, minp): - pos = index * self.resolution + minp - return pos - - def calc_xy_index(self, position, minp): - return round((position - minp) / self.resolution) - - def calc_index(self, node): - return (node.y - self.min_y) * self.x_width + (node.x - self.min_x) - - def verify_node(self, node): - px = self.calc_position(node.x, self.min_x) - py = self.calc_position(node.y, self.min_y) - - if px < self.min_x: - return False - if py < self.min_y: - return False - if px >= self.max_x: - return False - if py >= self.max_y: - return False - - if self.obstacle_map[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.min_x = round(min(ox)) - self.min_y = round(min(oy)) - self.max_x = round(max(ox)) - self.max_y = round(max(oy)) - print("min_x:", self.min_x) - print("min_y:", self.min_y) - print("max_x:", self.max_x) - print("max_y:", self.max_y) - - self.x_width = round((self.max_x - self.min_x) / self.resolution) - self.y_width = round((self.max_y - self.min_y) / self.resolution) - print("x_width:", self.x_width) - print("y_width:", self.y_width) - - # obstacle map generation - self.obstacle_map = [[False for _ in range(self.y_width)] - for _ in range(self.x_width)] - for ix in range(self.x_width): - x = self.calc_position(ix, self.min_x) - for iy in range(self.y_width): - y = self.calc_position(iy, self.min_y) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.robot_radius: - self.obstacle_map[ix][iy] = True - break - - @staticmethod - 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 - - -def main(): - print(__file__ + " start!!") - - # start and goal position - sx = -5.0 # [m] - sy = -5.0 # [m] - gx = 50.0 # [m] - gy = 50.0 # [m] - grid_size = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(float(i)) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(float(i)) - for i in range(-10, 61): - ox.append(float(i)) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(float(i)) - for i in range(-10, 40): - ox.append(20.0) - oy.append(float(i)) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "xb") - plt.grid(True) - plt.axis("equal") - - dijkstra = Dijkstra(ox, oy, grid_size, robot_radius) - rx, ry = dijkstra.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.01) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/DubinsPath/__init__.py b/PathPlanning/DubinsPath/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/DubinsPath/dubins_path_planner.py b/PathPlanning/DubinsPath/dubins_path_planner.py deleted file mode 100644 index a7e8a100cc3..00000000000 --- a/PathPlanning/DubinsPath/dubins_path_planner.py +++ /dev/null @@ -1,317 +0,0 @@ -""" - -Dubins path planner sample code - -author Atsushi Sakai(@Atsushi_twi) - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -from math import sin, cos, atan2, sqrt, acos, pi, hypot -import numpy as np -from utils.angle import angle_mod, rot_mat_2d - -show_animation = True - - -def plan_dubins_path(s_x, s_y, s_yaw, g_x, g_y, g_yaw, curvature, - step_size=0.1, selected_types=None): - """ - Plan dubins path - - Parameters - ---------- - s_x : float - x position of the start point [m] - s_y : float - y position of the start point [m] - s_yaw : float - yaw angle of the start point [rad] - g_x : float - x position of the goal point [m] - g_y : float - y position of the end point [m] - g_yaw : float - yaw angle of the end point [rad] - curvature : float - curvature for curve [1/m] - step_size : float (optional) - step size between two path points [m]. Default is 0.1 - selected_types : a list of string or None - selected path planning types. If None, all types are used for - path planning, and minimum path length result is returned. - You can select used path plannings types by a string list. - e.g.: ["RSL", "RSR"] - - Returns - ------- - x_list: array - x positions of the path - y_list: array - y positions of the path - yaw_list: array - yaw angles of the path - modes: array - mode list of the path - lengths: array - arrow_length list of the path segments. - - Examples - -------- - You can generate a dubins path. - - >>> start_x = 1.0 # [m] - >>> start_y = 1.0 # [m] - >>> start_yaw = np.deg2rad(45.0) # [rad] - >>> end_x = -3.0 # [m] - >>> end_y = -3.0 # [m] - >>> end_yaw = np.deg2rad(-45.0) # [rad] - >>> curvature = 1.0 - >>> path_x, path_y, path_yaw, mode, _ = plan_dubins_path( - start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature) - >>> plt.plot(path_x, path_y, label="final course " + "".join(mode)) - >>> plot_arrow(start_x, start_y, start_yaw) - >>> plot_arrow(end_x, end_y, end_yaw) - >>> plt.legend() - >>> plt.grid(True) - >>> plt.axis("equal") - >>> plt.show() - - .. image:: dubins_path.jpg - """ - if selected_types is None: - planning_funcs = _PATH_TYPE_MAP.values() - else: - planning_funcs = [_PATH_TYPE_MAP[ptype] for ptype in selected_types] - - # calculate local goal x, y, yaw - l_rot = rot_mat_2d(s_yaw) - le_xy = np.stack([g_x - s_x, g_y - s_y]).T @ l_rot - local_goal_x = le_xy[0] - local_goal_y = le_xy[1] - local_goal_yaw = g_yaw - s_yaw - - lp_x, lp_y, lp_yaw, modes, lengths = _dubins_path_planning_from_origin( - local_goal_x, local_goal_y, local_goal_yaw, curvature, step_size, - planning_funcs) - - # Convert a local coordinate path to the global coordinate - rot = rot_mat_2d(-s_yaw) - converted_xy = np.stack([lp_x, lp_y]).T @ rot - x_list = converted_xy[:, 0] + s_x - y_list = converted_xy[:, 1] + s_y - yaw_list = angle_mod(np.array(lp_yaw) + s_yaw) - - return x_list, y_list, yaw_list, modes, lengths - - -def _mod2pi(theta): - return angle_mod(theta, zero_2_2pi=True) - - -def _calc_trig_funcs(alpha, beta): - sin_a = sin(alpha) - sin_b = sin(beta) - cos_a = cos(alpha) - cos_b = cos(beta) - cos_ab = cos(alpha - beta) - return sin_a, sin_b, cos_a, cos_b, cos_ab - - -def _LSL(alpha, beta, d): - sin_a, sin_b, cos_a, cos_b, cos_ab = _calc_trig_funcs(alpha, beta) - mode = ["L", "S", "L"] - p_squared = 2 + d ** 2 - (2 * cos_ab) + (2 * d * (sin_a - sin_b)) - if p_squared < 0: # invalid configuration - return None, None, None, mode - tmp = atan2((cos_b - cos_a), d + sin_a - sin_b) - d1 = _mod2pi(-alpha + tmp) - d2 = sqrt(p_squared) - d3 = _mod2pi(beta - tmp) - return d1, d2, d3, mode - - -def _RSR(alpha, beta, d): - sin_a, sin_b, cos_a, cos_b, cos_ab = _calc_trig_funcs(alpha, beta) - mode = ["R", "S", "R"] - p_squared = 2 + d ** 2 - (2 * cos_ab) + (2 * d * (sin_b - sin_a)) - if p_squared < 0: - return None, None, None, mode - tmp = atan2((cos_a - cos_b), d - sin_a + sin_b) - d1 = _mod2pi(alpha - tmp) - d2 = sqrt(p_squared) - d3 = _mod2pi(-beta + tmp) - return d1, d2, d3, mode - - -def _LSR(alpha, beta, d): - sin_a, sin_b, cos_a, cos_b, cos_ab = _calc_trig_funcs(alpha, beta) - p_squared = -2 + d ** 2 + (2 * cos_ab) + (2 * d * (sin_a + sin_b)) - mode = ["L", "S", "R"] - if p_squared < 0: - return None, None, None, mode - d1 = sqrt(p_squared) - tmp = atan2((-cos_a - cos_b), (d + sin_a + sin_b)) - atan2(-2.0, d1) - d2 = _mod2pi(-alpha + tmp) - d3 = _mod2pi(-_mod2pi(beta) + tmp) - return d2, d1, d3, mode - - -def _RSL(alpha, beta, d): - sin_a, sin_b, cos_a, cos_b, cos_ab = _calc_trig_funcs(alpha, beta) - p_squared = d ** 2 - 2 + (2 * cos_ab) - (2 * d * (sin_a + sin_b)) - mode = ["R", "S", "L"] - if p_squared < 0: - return None, None, None, mode - d1 = sqrt(p_squared) - tmp = atan2((cos_a + cos_b), (d - sin_a - sin_b)) - atan2(2.0, d1) - d2 = _mod2pi(alpha - tmp) - d3 = _mod2pi(beta - tmp) - return d2, d1, d3, mode - - -def _RLR(alpha, beta, d): - sin_a, sin_b, cos_a, cos_b, cos_ab = _calc_trig_funcs(alpha, beta) - mode = ["R", "L", "R"] - tmp = (6.0 - d ** 2 + 2.0 * cos_ab + 2.0 * d * (sin_a - sin_b)) / 8.0 - if abs(tmp) > 1.0: - return None, None, None, mode - d2 = _mod2pi(2 * pi - acos(tmp)) - d1 = _mod2pi(alpha - atan2(cos_a - cos_b, d - sin_a + sin_b) + d2 / 2.0) - d3 = _mod2pi(alpha - beta - d1 + d2) - return d1, d2, d3, mode - - -def _LRL(alpha, beta, d): - sin_a, sin_b, cos_a, cos_b, cos_ab = _calc_trig_funcs(alpha, beta) - mode = ["L", "R", "L"] - tmp = (6.0 - d ** 2 + 2.0 * cos_ab + 2.0 * d * (- sin_a + sin_b)) / 8.0 - if abs(tmp) > 1.0: - return None, None, None, mode - d2 = _mod2pi(2 * pi - acos(tmp)) - d1 = _mod2pi(-alpha - atan2(cos_a - cos_b, d + sin_a - sin_b) + d2 / 2.0) - d3 = _mod2pi(_mod2pi(beta) - alpha - d1 + _mod2pi(d2)) - return d1, d2, d3, mode - - -_PATH_TYPE_MAP = {"LSL": _LSL, "RSR": _RSR, "LSR": _LSR, "RSL": _RSL, - "RLR": _RLR, "LRL": _LRL, } - - -def _dubins_path_planning_from_origin(end_x, end_y, end_yaw, curvature, - step_size, planning_funcs): - dx = end_x - dy = end_y - d = hypot(dx, dy) * curvature - - theta = _mod2pi(atan2(dy, dx)) - alpha = _mod2pi(-theta) - beta = _mod2pi(end_yaw - theta) - - best_cost = float("inf") - b_d1, b_d2, b_d3, b_mode = None, None, None, None - - for planner in planning_funcs: - d1, d2, d3, mode = planner(alpha, beta, d) - if d1 is None: - continue - - cost = (abs(d1) + abs(d2) + abs(d3)) - if best_cost > cost: # Select minimum length one. - b_d1, b_d2, b_d3, b_mode, best_cost = d1, d2, d3, mode, cost - - lengths = [b_d1, b_d2, b_d3] - x_list, y_list, yaw_list = _generate_local_course(lengths, b_mode, - curvature, step_size) - - lengths = [length / curvature for length in lengths] - - return x_list, y_list, yaw_list, b_mode, lengths - - -def _interpolate(length, mode, max_curvature, origin_x, origin_y, - origin_yaw, path_x, path_y, path_yaw): - if mode == "S": - path_x.append(origin_x + length / max_curvature * cos(origin_yaw)) - path_y.append(origin_y + length / max_curvature * sin(origin_yaw)) - path_yaw.append(origin_yaw) - else: # curve - ldx = sin(length) / max_curvature - ldy = 0.0 - if mode == "L": # left turn - ldy = (1.0 - cos(length)) / max_curvature - elif mode == "R": # right turn - ldy = (1.0 - cos(length)) / -max_curvature - gdx = cos(-origin_yaw) * ldx + sin(-origin_yaw) * ldy - gdy = -sin(-origin_yaw) * ldx + cos(-origin_yaw) * ldy - path_x.append(origin_x + gdx) - path_y.append(origin_y + gdy) - - if mode == "L": # left turn - path_yaw.append(origin_yaw + length) - elif mode == "R": # right turn - path_yaw.append(origin_yaw - length) - - return path_x, path_y, path_yaw - - -def _generate_local_course(lengths, modes, max_curvature, step_size): - p_x, p_y, p_yaw = [0.0], [0.0], [0.0] - - for (mode, length) in zip(modes, lengths): - if length == 0.0: - continue - - # set origin state - origin_x, origin_y, origin_yaw = p_x[-1], p_y[-1], p_yaw[-1] - - current_length = step_size - while abs(current_length + step_size) <= abs(length): - p_x, p_y, p_yaw = _interpolate(current_length, mode, max_curvature, - origin_x, origin_y, origin_yaw, - p_x, p_y, p_yaw) - current_length += step_size - - p_x, p_y, p_yaw = _interpolate(length, mode, max_curvature, origin_x, - origin_y, origin_yaw, p_x, p_y, p_yaw) - - return p_x, p_y, p_yaw - - -def main(): - print("Dubins path planner sample start!!") - import matplotlib.pyplot as plt - from utils.plot import plot_arrow - - start_x = 1.0 # [m] - start_y = 1.0 # [m] - start_yaw = np.deg2rad(45.0) # [rad] - - end_x = -3.0 # [m] - end_y = -3.0 # [m] - end_yaw = np.deg2rad(-45.0) # [rad] - - curvature = 1.0 - - path_x, path_y, path_yaw, mode, lengths = plan_dubins_path(start_x, - start_y, - start_yaw, - end_x, - end_y, - end_yaw, - curvature) - - if show_animation: - plt.plot(path_x, path_y, label="".join(mode)) - plot_arrow(start_x, start_y, start_yaw) - plot_arrow(end_x, end_y, end_yaw) - plt.legend() - plt.grid(True) - plt.axis("equal") - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/DynamicMovementPrimitives/dynamic_movement_primitives.py b/PathPlanning/DynamicMovementPrimitives/dynamic_movement_primitives.py deleted file mode 100644 index 9ccd18b7c23..00000000000 --- a/PathPlanning/DynamicMovementPrimitives/dynamic_movement_primitives.py +++ /dev/null @@ -1,260 +0,0 @@ -""" -Author: Jonathan Schwartz (github.com/SchwartzCode) - -This code provides a simple implementation of Dynamic Movement -Primitives, which is an approach to learning curves by modelling -them as a weighted sum of gaussian distributions. This approach -can be used to dampen noise in a curve, and can also be used to -stretch a curve by adjusting its start and end points. - -More information on Dynamic Movement Primitives available at: -https://arxiv.org/abs/2102.03861 -https://www.frontiersin.org/journals/computational-neuroscience/articles/10.3389/fncom.2013.00138/full - -""" - - -from matplotlib import pyplot as plt -import numpy as np - - -class DMP: - - def __init__(self, training_data, data_period, K=156.25, B=25): - """ - Arguments: - training_data - input data of form [N, dim] - data_period - amount of time training data covers - K and B - spring and damper constants to define - DMP behavior - """ - - self.K = K # virtual spring constant - self.B = B # virtual damper coefficient - - self.timesteps = training_data.shape[0] - self.dt = data_period / self.timesteps - - self.weights = None # weights used to generate DMP trajectories - - self.T_orig = data_period - - self.training_data = training_data - self.find_basis_functions_weights(training_data, data_period) - - def find_basis_functions_weights(self, training_data, data_period, - num_weights=10): - """ - Arguments: - data [(steps x spacial dim) np array] - data to replicate with DMP - data_period [float] - time duration of data - """ - - if not isinstance(training_data, np.ndarray): - print("Warning: you should input training data as an np.ndarray") - elif training_data.shape[0] < training_data.shape[1]: - print("Warning: you probably need to transpose your training data") - - dt = data_period / len(training_data) - - init_state = training_data[0] - goal_state = training_data[-1] - - # means (C) and std devs (H) of gaussian basis functions - C = np.linspace(0, 1, num_weights) - H = (0.65*(1./(num_weights-1))**2) - - for dim, _ in enumerate(training_data[0]): - - dimension_data = training_data[:, dim] - - q0 = init_state[dim] - g = goal_state[dim] - - q = q0 - qd_last = 0 - - phi_vals = [] - f_vals = [] - - for i, _ in enumerate(dimension_data): - if i + 1 == len(dimension_data): - qd = 0 - else: - qd = (dimension_data[i+1] - dimension_data[i]) / dt - - phi = [np.exp(-0.5 * ((i * dt / data_period) - c)**2 / H) - for c in C] - phi = phi/np.sum(phi) - - qdd = (qd - qd_last)/dt - - f = (qdd * data_period**2 - self.K * (g - q) + self.B * qd - * data_period) / (g - q0) - - phi_vals.append(phi) - f_vals.append(f) - - qd_last = qd - q += qd * dt - - phi_vals = np.asarray(phi_vals) - f_vals = np.asarray(f_vals) - - w = np.linalg.lstsq(phi_vals, f_vals, rcond=None) - - if self.weights is None: - self.weights = np.asarray(w[0]) - else: - self.weights = np.vstack([self.weights, w[0]]) - - def recreate_trajectory(self, init_state, goal_state, T): - """ - init_state - initial state/position - goal_state - goal state/position - T - amount of time to travel q0 -> g - """ - - nrBasis = len(self.weights[0]) # number of gaussian basis functions - - # means (C) and std devs (H) of gaussian basis functions - C = np.linspace(0, 1, nrBasis) - H = (0.65*(1./(nrBasis-1))**2) - - # initialize virtual system - time = 0 - - q = init_state - dimensions = self.weights.shape[0] - qd = np.zeros(dimensions) - - positions = np.array([]) - for k in range(self.timesteps): - time = time + self.dt - - qdd = np.zeros(dimensions) - - for dim in range(dimensions): - - if time <= T: - phi = [np.exp(-0.5 * ((time / T) - c)**2 / H) for c in C] - phi = phi / np.sum(phi) - f = np.dot(phi, self.weights[dim]) - else: - f = 0 - - # simulate dynamics - qdd[dim] = (self.K*(goal_state[dim] - q[dim])/T**2 - - self.B*qd[dim]/T - + (goal_state[dim] - init_state[dim])*f/T**2) - - qd = qd + qdd * self.dt - q = q + qd * self.dt - - if positions.size == 0: - positions = q - else: - positions = np.vstack([positions, q]) - - t = np.arange(0, self.timesteps * self.dt, self.dt) - return t, positions - - @staticmethod - def dist_between(p1, p2): - return np.linalg.norm(p1 - p2) - - def view_trajectory(self, path, title=None, demo=False): - - path = np.asarray(path) - - plt.cla() - plt.plot(self.training_data[:, 0], self.training_data[:, 1], - label="Training Data") - plt.plot(path[:, 0], path[:, 1], - linewidth=2, label="DMP Approximation") - - plt.xlabel("X Position") - plt.ylabel("Y Position") - plt.legend() - - if title is not None: - plt.title(title) - - if demo: - plt.xlim([-0.5, 5]) - plt.ylim([-2, 2]) - plt.draw() - plt.pause(0.02) - else: - plt.show() - - def show_DMP_purpose(self): - """ - This function conveys the purpose of DMPs: - to capture a trajectory and be able to stretch - and squeeze it in terms of start and stop position - or time - """ - - q0_orig = self.training_data[0] - g_orig = self.training_data[-1] - T_orig = self.T_orig - - data_range = (np.amax(self.training_data[:, 0]) - - np.amin(self.training_data[:, 0])) / 4 - - q0_right = q0_orig + np.array([data_range, 0]) - q0_up = q0_orig + np.array([0, data_range/2]) - g_left = g_orig - np.array([data_range, 0]) - g_down = g_orig - np.array([0, data_range/2]) - - q0_vals = np.vstack([np.linspace(q0_orig, q0_right, 20), - np.linspace(q0_orig, q0_up, 20)]) - g_vals = np.vstack([np.linspace(g_orig, g_left, 20), - np.linspace(g_orig, g_down, 20)]) - T_vals = np.linspace(T_orig, 2*T_orig, 20) - - for new_q0_value in q0_vals: - plot_title = (f"Initial Position = [{round(new_q0_value[0], 2)}," - f" {round(new_q0_value[1], 2)}]") - - _, path = self.recreate_trajectory(new_q0_value, g_orig, T_orig) - self.view_trajectory(path, title=plot_title, demo=True) - - for new_g_value in g_vals: - plot_title = (f"Goal Position = [{round(new_g_value[0], 2)}," - f" {round(new_g_value[1], 2)}]") - - _, path = self.recreate_trajectory(q0_orig, new_g_value, T_orig) - self.view_trajectory(path, title=plot_title, demo=True) - - for new_T_value in T_vals: - plot_title = f"Period = {round(new_T_value, 2)} [sec]" - - _, path = self.recreate_trajectory(q0_orig, g_orig, new_T_value) - self.view_trajectory(path, title=plot_title, demo=True) - - -def example_DMP(): - """ - Creates a noisy trajectory, fits weights to it, and then adjusts the - trajectory by moving its start position, goal position, or period - """ - t = np.arange(0, 3*np.pi/2, 0.01) - t1 = np.arange(3*np.pi/2, 2*np.pi, 0.01)[:-1] - t2 = np.arange(0, np.pi/2, 0.01)[:-1] - t3 = np.arange(np.pi, 3*np.pi/2, 0.01) - data_x = t + 0.02*np.random.rand(t.shape[0]) - data_y = np.concatenate([np.cos(t1) + 0.1*np.random.rand(t1.shape[0]), - np.cos(t2) + 0.1*np.random.rand(t2.shape[0]), - np.sin(t3) + 0.1*np.random.rand(t3.shape[0])]) - training_data = np.vstack([data_x, data_y]).T - - period = 3*np.pi/2 - DMP_controller = DMP(training_data, period) - - DMP_controller.show_DMP_purpose() - - -if __name__ == '__main__': - example_DMP() diff --git a/PathPlanning/DynamicWindowApproach/dynamic_window_approach.py b/PathPlanning/DynamicWindowApproach/dynamic_window_approach.py deleted file mode 100644 index 8664ec1745a..00000000000 --- a/PathPlanning/DynamicWindowApproach/dynamic_window_approach.py +++ /dev/null @@ -1,308 +0,0 @@ -""" - -Mobile robot motion planning sample with Dynamic Window Approach - -author: Atsushi Sakai (@Atsushi_twi), Göktuğ Karakaşlı - -""" - -import math -from enum import Enum - -import matplotlib.pyplot as plt -import numpy as np - -show_animation = True - - -def dwa_control(x, config, goal, ob): - """ - Dynamic Window Approach control - """ - dw = calc_dynamic_window(x, config) - - u, trajectory = calc_control_and_trajectory(x, dw, config, goal, ob) - - return u, trajectory - - -class RobotType(Enum): - circle = 0 - rectangle = 1 - - -class Config: - """ - simulation parameter class - """ - - def __init__(self): - # robot parameter - self.max_speed = 1.0 # [m/s] - self.min_speed = -0.5 # [m/s] - self.max_yaw_rate = 40.0 * math.pi / 180.0 # [rad/s] - self.max_accel = 0.2 # [m/ss] - self.max_delta_yaw_rate = 40.0 * math.pi / 180.0 # [rad/ss] - self.v_resolution = 0.01 # [m/s] - self.yaw_rate_resolution = 0.1 * math.pi / 180.0 # [rad/s] - self.dt = 0.1 # [s] Time tick for motion prediction - self.predict_time = 3.0 # [s] - self.to_goal_cost_gain = 0.15 - self.speed_cost_gain = 1.0 - self.obstacle_cost_gain = 1.0 - self.robot_stuck_flag_cons = 0.001 # constant to prevent robot stucked - self.robot_type = RobotType.circle - - # if robot_type == RobotType.circle - # Also used to check if goal is reached in both types - self.robot_radius = 1.0 # [m] for collision check - - # if robot_type == RobotType.rectangle - self.robot_width = 0.5 # [m] for collision check - self.robot_length = 1.2 # [m] for collision check - # obstacles [x(m) y(m), ....] - self.ob = np.array([[-1, -1], - [0, 2], - [4.0, 2.0], - [5.0, 4.0], - [5.0, 5.0], - [5.0, 6.0], - [5.0, 9.0], - [8.0, 9.0], - [7.0, 9.0], - [8.0, 10.0], - [9.0, 11.0], - [12.0, 13.0], - [12.0, 12.0], - [15.0, 15.0], - [13.0, 13.0] - ]) - - @property - def robot_type(self): - return self._robot_type - - @robot_type.setter - def robot_type(self, value): - if not isinstance(value, RobotType): - raise TypeError("robot_type must be an instance of RobotType") - self._robot_type = value - - -config = Config() - - -def motion(x, u, dt): - """ - motion model - """ - - x[2] += u[1] * dt - x[0] += u[0] * math.cos(x[2]) * dt - x[1] += u[0] * math.sin(x[2]) * dt - x[3] = u[0] - x[4] = u[1] - - return x - - -def calc_dynamic_window(x, config): - """ - calculation dynamic window based on current state x - """ - - # Dynamic window from robot specification - Vs = [config.min_speed, config.max_speed, - -config.max_yaw_rate, config.max_yaw_rate] - - # Dynamic window from motion model - Vd = [x[3] - config.max_accel * config.dt, - x[3] + config.max_accel * config.dt, - x[4] - config.max_delta_yaw_rate * config.dt, - x[4] + config.max_delta_yaw_rate * config.dt] - - # [v_min, v_max, yaw_rate_min, yaw_rate_max] - dw = [max(Vs[0], Vd[0]), min(Vs[1], Vd[1]), - max(Vs[2], Vd[2]), min(Vs[3], Vd[3])] - - return dw - - -def predict_trajectory(x_init, v, y, config): - """ - predict trajectory with an input - """ - - x = np.array(x_init) - trajectory = np.array(x) - time = 0 - while time <= config.predict_time: - x = motion(x, [v, y], config.dt) - trajectory = np.vstack((trajectory, x)) - time += config.dt - - return trajectory - - -def calc_control_and_trajectory(x, dw, config, goal, ob): - """ - calculation final input with dynamic window - """ - - x_init = x[:] - min_cost = float("inf") - best_u = [0.0, 0.0] - best_trajectory = np.array([x]) - - # evaluate all trajectory with sampled input in dynamic window - for v in np.arange(dw[0], dw[1], config.v_resolution): - for y in np.arange(dw[2], dw[3], config.yaw_rate_resolution): - - trajectory = predict_trajectory(x_init, v, y, config) - # calc cost - to_goal_cost = config.to_goal_cost_gain * calc_to_goal_cost(trajectory, goal) - speed_cost = config.speed_cost_gain * (config.max_speed - trajectory[-1, 3]) - ob_cost = config.obstacle_cost_gain * calc_obstacle_cost(trajectory, ob, config) - - final_cost = to_goal_cost + speed_cost + ob_cost - - # search minimum trajectory - if min_cost >= final_cost: - min_cost = final_cost - best_u = [v, y] - best_trajectory = trajectory - if abs(best_u[0]) < config.robot_stuck_flag_cons \ - and abs(x[3]) < config.robot_stuck_flag_cons: - # to ensure the robot do not get stuck in - # best v=0 m/s (in front of an obstacle) and - # best omega=0 rad/s (heading to the goal with - # angle difference of 0) - best_u[1] = -config.max_delta_yaw_rate - return best_u, best_trajectory - - -def calc_obstacle_cost(trajectory, ob, config): - """ - calc obstacle cost inf: collision - """ - ox = ob[:, 0] - oy = ob[:, 1] - dx = trajectory[:, 0] - ox[:, None] - dy = trajectory[:, 1] - oy[:, None] - r = np.hypot(dx, dy) - - if config.robot_type == RobotType.rectangle: - yaw = trajectory[:, 2] - rot = np.array([[np.cos(yaw), -np.sin(yaw)], [np.sin(yaw), np.cos(yaw)]]) - rot = np.transpose(rot, [2, 0, 1]) - local_ob = ob[:, None] - trajectory[:, 0:2] - local_ob = local_ob.reshape(-1, local_ob.shape[-1]) - local_ob = np.array([local_ob @ x for x in rot]) - local_ob = local_ob.reshape(-1, local_ob.shape[-1]) - upper_check = local_ob[:, 0] <= config.robot_length / 2 - right_check = local_ob[:, 1] <= config.robot_width / 2 - bottom_check = local_ob[:, 0] >= -config.robot_length / 2 - left_check = local_ob[:, 1] >= -config.robot_width / 2 - if (np.logical_and(np.logical_and(upper_check, right_check), - np.logical_and(bottom_check, left_check))).any(): - return float("Inf") - elif config.robot_type == RobotType.circle: - if np.array(r <= config.robot_radius).any(): - return float("Inf") - - min_r = np.min(r) - return 1.0 / min_r # OK - - -def calc_to_goal_cost(trajectory, goal): - """ - calc to goal cost with angle difference - """ - - dx = goal[0] - trajectory[-1, 0] - dy = goal[1] - trajectory[-1, 1] - error_angle = math.atan2(dy, dx) - cost_angle = error_angle - trajectory[-1, 2] - cost = abs(math.atan2(math.sin(cost_angle), math.cos(cost_angle))) - - return cost - - -def plot_arrow(x, y, yaw, length=0.5, width=0.1): # pragma: no cover - plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw), - head_length=width, head_width=width) - plt.plot(x, y) - - -def plot_robot(x, y, yaw, config): # pragma: no cover - if config.robot_type == RobotType.rectangle: - outline = np.array([[-config.robot_length / 2, config.robot_length / 2, - (config.robot_length / 2), -config.robot_length / 2, - -config.robot_length / 2], - [config.robot_width / 2, config.robot_width / 2, - - config.robot_width / 2, -config.robot_width / 2, - config.robot_width / 2]]) - Rot1 = np.array([[math.cos(yaw), math.sin(yaw)], - [-math.sin(yaw), math.cos(yaw)]]) - outline = (outline.T.dot(Rot1)).T - outline[0, :] += x - outline[1, :] += y - plt.plot(np.array(outline[0, :]).flatten(), - np.array(outline[1, :]).flatten(), "-k") - elif config.robot_type == RobotType.circle: - circle = plt.Circle((x, y), config.robot_radius, color="b") - plt.gcf().gca().add_artist(circle) - out_x, out_y = (np.array([x, y]) + - np.array([np.cos(yaw), np.sin(yaw)]) * config.robot_radius) - plt.plot([x, out_x], [y, out_y], "-k") - - -def main(gx=10.0, gy=10.0, robot_type=RobotType.circle): - print(__file__ + " start!!") - # initial state [x(m), y(m), yaw(rad), v(m/s), omega(rad/s)] - x = np.array([0.0, 0.0, math.pi / 8.0, 0.0, 0.0]) - # goal position [x(m), y(m)] - goal = np.array([gx, gy]) - - # input [forward speed, yaw_rate] - - config.robot_type = robot_type - trajectory = np.array(x) - ob = config.ob - while True: - u, predicted_trajectory = dwa_control(x, config, goal, ob) - x = motion(x, u, config.dt) # simulate robot - trajectory = np.vstack((trajectory, x)) # store state history - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(predicted_trajectory[:, 0], predicted_trajectory[:, 1], "-g") - plt.plot(x[0], x[1], "xr") - plt.plot(goal[0], goal[1], "xb") - plt.plot(ob[:, 0], ob[:, 1], "ok") - plot_robot(x[0], x[1], x[2], config) - plot_arrow(x[0], x[1], x[2]) - plt.axis("equal") - plt.grid(True) - plt.pause(0.0001) - - # check reaching goal - dist_to_goal = math.hypot(x[0] - goal[0], x[1] - goal[1]) - if dist_to_goal <= config.robot_radius: - print("Goal!!") - break - - print("Done") - if show_animation: - plt.plot(trajectory[:, 0], trajectory[:, 1], "-r") - plt.pause(0.0001) - plt.show() - - -if __name__ == '__main__': - main(robot_type=RobotType.rectangle) - # main(robot_type=RobotType.circle) diff --git a/PathPlanning/ElasticBands/elastic_bands.py b/PathPlanning/ElasticBands/elastic_bands.py deleted file mode 100644 index 785f822d141..00000000000 --- a/PathPlanning/ElasticBands/elastic_bands.py +++ /dev/null @@ -1,300 +0,0 @@ -""" -Elastic Bands - -author: Wang Zheng (@Aglargil) - -Ref: - -- [Elastic Bands: Connecting Path Planning and Control] -(http://www8.cs.umu.se/research/ifor/dl/Control/elastic%20bands.pdf) -""" - -import numpy as np -import sys -import pathlib -import matplotlib.pyplot as plt -from matplotlib.patches import Circle - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -from Mapping.DistanceMap.distance_map import compute_sdf_scipy - -# Elastic Bands Params -MAX_BUBBLE_RADIUS = 100 -MIN_BUBBLE_RADIUS = 10 -RHO0 = 20.0 # Maximum distance for applying repulsive force -KC = 0.05 # Contraction force gain -KR = -0.1 # Repulsive force gain -LAMBDA = 0.7 # Overlap constraint factor -STEP_SIZE = 3.0 # Step size for calculating gradient - -# Visualization Params -ENABLE_PLOT = True -# ENABLE_INTERACTIVE is True allows user to add obstacles by left clicking -# and add path points by right clicking and start planning by middle clicking -ENABLE_INTERACTIVE = False -# ENABLE_SAVE_DATA is True allows saving the path and obstacles which added -# by user in interactive mode to file -ENABLE_SAVE_DATA = False -MAX_ITER = 50 - - -class Bubble: - def __init__(self, position, radius): - self.pos = np.array(position) # Bubble center coordinates [x, y] - self.radius = radius # Safety distance radius ρ(b) - if self.radius > MAX_BUBBLE_RADIUS: - self.radius = MAX_BUBBLE_RADIUS - if self.radius < MIN_BUBBLE_RADIUS: - self.radius = MIN_BUBBLE_RADIUS - - -class ElasticBands: - def __init__( - self, - initial_path, - obstacles, - rho0=RHO0, - kc=KC, - kr=KR, - lambda_=LAMBDA, - step_size=STEP_SIZE, - ): - self.distance_map = compute_sdf_scipy(obstacles) - self.bubbles = [ - Bubble(p, self.compute_rho(p)) for p in initial_path - ] # Initialize bubble chain - self.kc = kc # Contraction force gain - self.kr = kr # Repulsive force gain - self.rho0 = rho0 # Maximum distance for applying repulsive force - self.lambda_ = lambda_ # Overlap constraint factor - self.step_size = step_size # Step size for calculating gradient - self._maintain_overlap() - - def compute_rho(self, position): - """Compute the distance field value at the position""" - return self.distance_map[int(position[0]), int(position[1])] - - def contraction_force(self, i): - """Calculate internal contraction force for the i-th bubble""" - if i == 0 or i == len(self.bubbles) - 1: - return np.zeros(2) - - prev = self.bubbles[i - 1].pos - next_ = self.bubbles[i + 1].pos - current = self.bubbles[i].pos - - # f_c = kc * ( (prev-current)/|prev-current| + (next-current)/|next-current| ) - dir_prev = (prev - current) / (np.linalg.norm(prev - current) + 1e-6) - dir_next = (next_ - current) / (np.linalg.norm(next_ - current) + 1e-6) - return self.kc * (dir_prev + dir_next) - - def repulsive_force(self, i): - """Calculate external repulsive force for the i-th bubble""" - h = self.step_size # Step size - b = self.bubbles[i].pos - rho = self.bubbles[i].radius - - if rho >= self.rho0: - return np.zeros(2) - - # Finite difference approximation of the gradient ∂ρ/∂b - dx = np.array([h, 0]) - dy = np.array([0, h]) - grad_x = (self.compute_rho(b - dx) - self.compute_rho(b + dx)) / (2 * h) - grad_y = (self.compute_rho(b - dy) - self.compute_rho(b + dy)) / (2 * h) - grad = np.array([grad_x, grad_y]) - - return self.kr * (self.rho0 - rho) * grad - - def update_bubbles(self): - """Update bubble positions""" - new_bubbles = [] - for i in range(len(self.bubbles)): - if i == 0 or i == len(self.bubbles) - 1: - new_bubbles.append(self.bubbles[i]) # Fixed start and end points - continue - - f_total = self.contraction_force(i) + self.repulsive_force(i) - v = self.bubbles[i - 1].pos - self.bubbles[i + 1].pos - - # Remove tangential component - f_star = f_total - f_total * v * v / (np.linalg.norm(v) ** 2 + 1e-6) - - alpha = self.bubbles[i].radius # Adaptive step size - new_pos = self.bubbles[i].pos + alpha * f_star - new_pos = np.clip(new_pos, 0, 499) - new_radius = self.compute_rho(new_pos) - - # Update bubble and maintain overlap constraint - new_bubble = Bubble(new_pos, new_radius) - new_bubbles.append(new_bubble) - - self.bubbles = new_bubbles - self._maintain_overlap() - - def _maintain_overlap(self): - """Maintain bubble chain continuity (simplified insertion/deletion mechanism)""" - # Insert bubbles - i = 0 - while i < len(self.bubbles) - 1: - bi, bj = self.bubbles[i], self.bubbles[i + 1] - dist = np.linalg.norm(bi.pos - bj.pos) - if dist > self.lambda_ * (bi.radius + bj.radius): - new_pos = (bi.pos + bj.pos) / 2 - rho = self.compute_rho( - new_pos - ) # Calculate new radius using environment model - self.bubbles.insert(i + 1, Bubble(new_pos, rho)) - i += 2 # Skip the processed region - else: - i += 1 - - # Delete redundant bubbles - i = 1 - while i < len(self.bubbles) - 1: - prev = self.bubbles[i - 1] - next_ = self.bubbles[i + 1] - dist = np.linalg.norm(prev.pos - next_.pos) - if dist <= self.lambda_ * (prev.radius + next_.radius): - del self.bubbles[i] # Delete if redundant - else: - i += 1 - - -class ElasticBandsVisualizer: - def __init__(self): - self.obstacles = np.zeros((500, 500)) - self.obstacles_points = [] - self.path_points = [] - self.elastic_band = None - self.running = True - - if ENABLE_PLOT: - self.fig, self.ax = plt.subplots(figsize=(8, 8)) - self.fig.canvas.mpl_connect("close_event", self.on_close) - self.ax.set_xlim(0, 500) - self.ax.set_ylim(0, 500) - - if ENABLE_INTERACTIVE: - self.path_points = [] # Add a list to store path points - # Connect mouse events - self.fig.canvas.mpl_connect("button_press_event", self.on_click) - else: - self.path_points = np.load(pathlib.Path(__file__).parent / "path.npy") - self.obstacles_points = np.load( - pathlib.Path(__file__).parent / "obstacles.npy" - ) - for x, y in self.obstacles_points: - self.add_obstacle(x, y) - self.plan_path() - - self.plot_background() - - def on_close(self, event): - """Handle window close event""" - self.running = False - plt.close("all") # Close all figure windows - - def plot_background(self): - """Plot the background grid""" - if not ENABLE_PLOT or not self.running: - return - - self.ax.cla() - self.ax.set_xlim(0, 500) - self.ax.set_ylim(0, 500) - self.ax.grid(True) - - if ENABLE_INTERACTIVE: - self.ax.set_title( - "Elastic Bands Path Planning\n" - "Left click: Add obstacles\n" - "Right click: Add path points\n" - "Middle click: Start planning", - pad=20, - ) - else: - self.ax.set_title("Elastic Bands Path Planning", pad=20) - - if self.path_points: - self.ax.plot( - [p[0] for p in self.path_points], - [p[1] for p in self.path_points], - "yo", - markersize=8, - ) - - self.ax.imshow(self.obstacles.T, origin="lower", cmap="binary", alpha=0.8) - self.ax.plot([], [], color="black", label="obstacles") - if self.elastic_band is not None: - path = [b.pos.tolist() for b in self.elastic_band.bubbles] - path = np.array(path) - self.ax.plot(path[:, 0], path[:, 1], "b-", linewidth=2, label="path") - - for bubble in self.elastic_band.bubbles: - circle = Circle( - bubble.pos, bubble.radius, fill=False, color="g", alpha=0.3 - ) - self.ax.add_patch(circle) - self.ax.plot(bubble.pos[0], bubble.pos[1], "bo", markersize=10) - self.ax.plot([], [], color="green", label="bubbles") - - self.ax.legend(loc="upper right") - plt.draw() - plt.pause(0.01) - - def add_obstacle(self, x, y): - """Add an obstacle at the given coordinates""" - size = 30 # Side length of the square - half_size = size // 2 - x_start = max(0, x - half_size) - x_end = min(self.obstacles.shape[0], x + half_size) - y_start = max(0, y - half_size) - y_end = min(self.obstacles.shape[1], y + half_size) - self.obstacles[x_start:x_end, y_start:y_end] = 1 - - def on_click(self, event): - """Handle mouse click events""" - if event.inaxes != self.ax: - return - - x, y = int(event.xdata), int(event.ydata) - - if event.button == 1: # Left click to add obstacles - self.add_obstacle(x, y) - self.obstacles_points.append([x, y]) - - elif event.button == 3: # Right click to add path points - self.path_points.append([x, y]) - - elif event.button == 2: # Middle click to end path input and start planning - if len(self.path_points) >= 2: - if ENABLE_SAVE_DATA: - np.save( - pathlib.Path(__file__).parent / "path.npy", self.path_points - ) - np.save( - pathlib.Path(__file__).parent / "obstacles.npy", - self.obstacles_points, - ) - self.plan_path() - - self.plot_background() - - def plan_path(self): - """Plan the path""" - - initial_path = self.path_points - # Create an elastic band object and optimize - self.elastic_band = ElasticBands(initial_path, self.obstacles) - for _ in range(MAX_ITER): - self.elastic_band.update_bubbles() - self.path_points = [b.pos for b in self.elastic_band.bubbles] - self.plot_background() - - -if __name__ == "__main__": - _ = ElasticBandsVisualizer() - if ENABLE_PLOT: - plt.show(block=True) diff --git a/PathPlanning/ElasticBands/obstacles.npy b/PathPlanning/ElasticBands/obstacles.npy deleted file mode 100644 index af4376afcf0..00000000000 Binary files a/PathPlanning/ElasticBands/obstacles.npy and /dev/null differ diff --git a/PathPlanning/ElasticBands/path.npy b/PathPlanning/ElasticBands/path.npy deleted file mode 100644 index be7c253d650..00000000000 Binary files a/PathPlanning/ElasticBands/path.npy and /dev/null differ diff --git a/PathPlanning/Eta3SplinePath/eta3_spline_path.py b/PathPlanning/Eta3SplinePath/eta3_spline_path.py deleted file mode 100644 index dc07d3c84b9..00000000000 --- a/PathPlanning/Eta3SplinePath/eta3_spline_path.py +++ /dev/null @@ -1,361 +0,0 @@ -""" - -eta^3 polynomials planner - -author: Joe Dinius, Ph.D (https://jwdinius.github.io) - Atsushi Sakai (@Atsushi_twi) - -Ref: -- [eta^3-Splines for the Smooth Path Generation of Wheeled Mobile Robots] -(https://ieeexplore.ieee.org/document/4339545/) - -""" - -import numpy as np -import matplotlib.pyplot as plt -from scipy.integrate import quad - -# NOTE: *_pose is a 3-array: -# 0 - x coord, 1 - y coord, 2 - orientation angle \theta - -show_animation = True - - -class Eta3Path(object): - """ - Eta3Path - - input - segments: a list of `Eta3PathSegment` instances - defining a continuous path - """ - - def __init__(self, segments): - # ensure input has the correct form - assert(isinstance(segments, list) and isinstance( - segments[0], Eta3PathSegment)) - # ensure that each segment begins from the previous segment's end (continuity) - for r, s in zip(segments[:-1], segments[1:]): - assert(np.array_equal(r.end_pose, s.start_pose)) - self.segments = segments - - def calc_path_point(self, u): - """ - Eta3Path::calc_path_point - - input - normalized interpolation point along path object, 0 <= u <= len(self.segments) - returns - 2d (x,y) position vector - """ - - assert(0 <= u <= len(self.segments)) - if np.isclose(u, len(self.segments)): - segment_idx = len(self.segments) - 1 - u = 1. - else: - segment_idx = int(np.floor(u)) - u -= segment_idx - return self.segments[segment_idx].calc_point(u) - - -class Eta3PathSegment(object): - """ - Eta3PathSegment - constructs an eta^3 path segment based on desired - shaping, eta, and curvature vector, kappa. If either, or both, - of eta and kappa are not set during initialization, - they will default to zeros. - - input - start_pose - starting pose array (x, y, \theta) - end_pose - ending pose array (x, y, \theta) - eta - shaping parameters, default=None - kappa - curvature parameters, default=None - """ - - def __init__(self, start_pose, end_pose, eta=None, kappa=None): - # make sure inputs are of the correct size - assert(len(start_pose) == 3 and len(start_pose) == len(end_pose)) - self.start_pose = start_pose - self.end_pose = end_pose - # if no eta is passed, initialize it to array of zeros - if not eta: - eta = np.zeros((6,)) - else: - # make sure that eta has correct size - assert(len(eta) == 6) - # if no kappa is passed, initialize to array of zeros - if not kappa: - kappa = np.zeros((4,)) - else: - assert(len(kappa) == 4) - # set up angle cosines and sines for simpler computations below - ca = np.cos(start_pose[2]) - sa = np.sin(start_pose[2]) - cb = np.cos(end_pose[2]) - sb = np.sin(end_pose[2]) - # 2 dimensions (x,y) x 8 coefficients per dimension - self.coeffs = np.empty((2, 8)) - # constant terms (u^0) - self.coeffs[0, 0] = start_pose[0] - self.coeffs[1, 0] = start_pose[1] - # linear (u^1) - self.coeffs[0, 1] = eta[0] * ca - self.coeffs[1, 1] = eta[0] * sa - # quadratic (u^2) - self.coeffs[0, 2] = 1. / 2 * eta[2] * \ - ca - 1. / 2 * eta[0]**2 * kappa[0] * sa - self.coeffs[1, 2] = 1. / 2 * eta[2] * \ - sa + 1. / 2 * eta[0]**2 * kappa[0] * ca - # cubic (u^3) - self.coeffs[0, 3] = 1. / 6 * eta[4] * ca - 1. / 6 * \ - (eta[0]**3 * kappa[1] + 3. * eta[0] * eta[2] * kappa[0]) * sa - self.coeffs[1, 3] = 1. / 6 * eta[4] * sa + 1. / 6 * \ - (eta[0]**3 * kappa[1] + 3. * eta[0] * eta[2] * kappa[0]) * ca - # quartic (u^4) - tmp1 = 35. * (end_pose[0] - start_pose[0]) - tmp2 = (20. * eta[0] + 5 * eta[2] + 2. / 3 * eta[4]) * ca - tmp3 = (5. * eta[0] ** 2 * kappa[0] + 2. / 3 * eta[0] ** 3 * kappa[1] - + 2. * eta[0] * eta[2] * kappa[0]) * sa - tmp4 = (15. * eta[1] - 5. / 2 * eta[3] + 1. / 6 * eta[5]) * cb - tmp5 = (5. / 2 * eta[1] ** 2 * kappa[2] - 1. / 6 * eta[1] ** 3 * - kappa[3] - 1. / 2 * eta[1] * eta[3] * kappa[2]) * sb - self.coeffs[0, 4] = tmp1 - tmp2 + tmp3 - tmp4 - tmp5 - tmp1 = 35. * (end_pose[1] - start_pose[1]) - tmp2 = (20. * eta[0] + 5. * eta[2] + 2. / 3 * eta[4]) * sa - tmp3 = (5. * eta[0] ** 2 * kappa[0] + 2. / 3 * eta[0] ** 3 * kappa[1] - + 2. * eta[0] * eta[2] * kappa[0]) * ca - tmp4 = (15. * eta[1] - 5. / 2 * eta[3] + 1. / 6 * eta[5]) * sb - tmp5 = (5. / 2 * eta[1] ** 2 * kappa[2] - 1. / 6 * eta[1] ** 3 * - kappa[3] - 1. / 2 * eta[1] * eta[3] * kappa[2]) * cb - self.coeffs[1, 4] = tmp1 - tmp2 - tmp3 - tmp4 + tmp5 - # quintic (u^5) - tmp1 = -84. * (end_pose[0] - start_pose[0]) - tmp2 = (45. * eta[0] + 10. * eta[2] + eta[4]) * ca - tmp3 = (10. * eta[0] ** 2 * kappa[0] + eta[0] ** 3 * kappa[1] + 3. * - eta[0] * eta[2] * kappa[0]) * sa - tmp4 = (39. * eta[1] - 7. * eta[3] + 1. / 2 * eta[5]) * cb - tmp5 = + (7. * eta[1] ** 2 * kappa[2] - 1. / 2 * eta[1] ** 3 * kappa[3] - - 3. / 2 * eta[1] * eta[3] * kappa[2]) * sb - self.coeffs[0, 5] = tmp1 + tmp2 - tmp3 + tmp4 + tmp5 - tmp1 = -84. * (end_pose[1] - start_pose[1]) - tmp2 = (45. * eta[0] + 10. * eta[2] + eta[4]) * sa - tmp3 = (10. * eta[0] ** 2 * kappa[0] + eta[0] ** 3 * kappa[1] + 3. * - eta[0] * eta[2] * kappa[0]) * ca - tmp4 = (39. * eta[1] - 7. * eta[3] + 1. / 2 * eta[5]) * sb - tmp5 = - (7. * eta[1] ** 2 * kappa[2] - 1. / 2 * eta[1] ** 3 * kappa[3] - - 3. / 2 * eta[1] * eta[3] * kappa[2]) * cb - self.coeffs[1, 5] = tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - # sextic (u^6) - tmp1 = 70. * (end_pose[0] - start_pose[0]) - tmp2 = (36. * eta[0] + 15. / 2 * eta[2] + 2. / 3 * eta[4]) * ca - tmp3 = + (15. / 2 * eta[0] ** 2 * kappa[0] + 2. / 3 * eta[0] ** 3 * - kappa[1] + 2. * eta[0] * eta[2] * kappa[0]) * sa - tmp4 = (34. * eta[1] - 13. / 2 * eta[3] + 1. / 2 * eta[5]) * cb - tmp5 = - (13. / 2 * eta[1] ** 2 * kappa[2] - 1. / 2 * eta[1] ** 3 * - kappa[3] - 3. / 2 * eta[1] * eta[3] * kappa[2]) * sb - self.coeffs[0, 6] = tmp1 - tmp2 + tmp3 - tmp4 + tmp5 - tmp1 = 70. * (end_pose[1] - start_pose[1]) - tmp2 = - (36. * eta[0] + 15. / 2 * eta[2] + 2. / 3 * eta[4]) * sa - tmp3 = - (15. / 2 * eta[0] ** 2 * kappa[0] + 2. / 3 * eta[0] ** 3 * - kappa[1] + 2. * eta[0] * eta[2] * kappa[0]) * ca - tmp4 = - (34. * eta[1] - 13. / 2 * eta[3] + 1. / 2 * eta[5]) * sb - tmp5 = + (13. / 2 * eta[1] ** 2 * kappa[2] - 1. / 2 * eta[1] ** 3 * - kappa[3] - 3. / 2 * eta[1] * eta[3] * kappa[2]) * cb - self.coeffs[1, 6] = tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - # septic (u^7) - tmp1 = -20. * (end_pose[0] - start_pose[0]) - tmp2 = (10. * eta[0] + 2. * eta[2] + 1. / 6 * eta[4]) * ca - tmp3 = - (2. * eta[0] ** 2 * kappa[0] + 1. / 6 * eta[0] ** 3 * kappa[1] - + 1. / 2 * eta[0] * eta[2] * kappa[0]) * sa - tmp4 = (10. * eta[1] - 2. * eta[3] + 1. / 6 * eta[5]) * cb - tmp5 = (2. * eta[1] ** 2 * kappa[2] - 1. / 6 * eta[1] ** 3 * kappa[3] - - 1. / 2 * eta[1] * eta[3] * kappa[2]) * sb - self.coeffs[0, 7] = tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - - tmp1 = -20. * (end_pose[1] - start_pose[1]) - tmp2 = (10. * eta[0] + 2. * eta[2] + 1. / 6 * eta[4]) * sa - tmp3 = (2. * eta[0] ** 2 * kappa[0] + 1. / 6 * eta[0] ** 3 * kappa[1] - + 1. / 2 * eta[0] * eta[2] * kappa[0]) * ca - tmp4 = (10. * eta[1] - 2. * eta[3] + 1. / 6 * eta[5]) * sb - tmp5 = - (2. * eta[1] ** 2 * kappa[2] - 1. / 6 * eta[1] ** 3 * kappa[3] - - 1. / 2 * eta[1] * eta[3] * kappa[2]) * cb - self.coeffs[1, 7] = tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - self.s_dot = lambda u: max(np.linalg.norm( - self.coeffs[:, 1:].dot(np.array( - [1, 2. * u, 3. * u**2, 4. * u**3, - 5. * u**4, 6. * u**5, 7. * u**6]))), 1e-6) - self.f_length = lambda ue: quad(lambda u: self.s_dot(u), 0, ue) - self.segment_length = self.f_length(1)[0] - - def calc_point(self, u): - """ - Eta3PathSegment::calc_point - - input - u - parametric representation of a point along the segment, 0 <= u <= 1 - returns - (x,y) of point along the segment - """ - assert(0 <= u <= 1) - return self.coeffs.dot(np.array([1, u, u**2, u**3, u**4, u**5, u**6, u**7])) - - def calc_deriv(self, u, order=1): - """ - Eta3PathSegment::calc_deriv - - input - u - parametric representation of a point along the segment, 0 <= u <= 1 - returns - (d^nx/du^n,d^ny/du^n) of point along the segment, for 0 < n <= 2 - """ - - assert(0 <= u <= 1) - assert(0 < order <= 2) - if order == 1: - return self.coeffs[:, 1:].dot(np.array([1, 2. * u, 3. * u**2, 4. * u**3, 5. * u**4, 6. * u**5, 7. * u**6])) - - return self.coeffs[:, 2:].dot(np.array([2, 6. * u, 12. * u**2, 20. * u**3, 30. * u**4, 42. * u**5])) - - -def test1(): - - for i in range(10): - path_segments = [] - # segment 1: lane-change curve - start_pose = [0, 0, 0] - end_pose = [4, 3.0, 0] - # NOTE: The ordering on kappa is [kappa_A, kappad_A, kappa_B, kappad_B], with kappad_* being the curvature derivative - kappa = [0, 0, 0, 0] - eta = [i, i, 0, 0, 0, 0] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - path = Eta3Path(path_segments) - - # interpolate at several points along the path - ui = np.linspace(0, len(path_segments), 1001) - pos = np.empty((2, ui.size)) - for j, u in enumerate(ui): - pos[:, j] = path.calc_path_point(u) - - if show_animation: - # plot the path - plt.plot(pos[0, :], pos[1, :]) - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.pause(1.0) - - if show_animation: - plt.close("all") - - -def test2(): - - for i in range(10): - path_segments = [] - # segment 1: lane-change curve - start_pose = [0, 0, 0] - end_pose = [4, 3.0, 0] - # NOTE: The ordering on kappa is [kappa_A, kappad_A, kappa_B, kappad_B], with kappad_* being the curvature derivative - kappa = [0, 0, 0, 0] - eta = [0, 0, (i - 5) * 20, (5 - i) * 20, 0, 0] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - path = Eta3Path(path_segments) - - # interpolate at several points along the path - ui = np.linspace(0, len(path_segments), 1001) - pos = np.empty((2, ui.size)) - for j, u in enumerate(ui): - pos[:, j] = path.calc_path_point(u) - - if show_animation: - # plot the path - plt.plot(pos[0, :], pos[1, :]) - plt.pause(1.0) - - if show_animation: - plt.close("all") - - -def test3(): - path_segments = [] - - # segment 1: lane-change curve - start_pose = [0, 0, 0] - end_pose = [4, 1.5, 0] - # NOTE: The ordering on kappa is [kappa_A, kappad_A, kappa_B, kappad_B], with kappad_* being the curvature derivative - kappa = [0, 0, 0, 0] - eta = [4.27, 4.27, 0, 0, 0, 0] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 2: line segment - start_pose = [4, 1.5, 0] - end_pose = [5.5, 1.5, 0] - kappa = [0, 0, 0, 0] - eta = [0, 0, 0, 0, 0, 0] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 3: cubic spiral - start_pose = [5.5, 1.5, 0] - end_pose = [7.4377, 1.8235, 0.6667] - kappa = [0, 0, 1, 1] - eta = [1.88, 1.88, 0, 0, 0, 0] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 4: generic twirl arc - start_pose = [7.4377, 1.8235, 0.6667] - end_pose = [7.8, 4.3, 1.8] - kappa = [1, 1, 0.5, 0] - eta = [7, 10, 10, -10, 4, 4] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 5: circular arc - start_pose = [7.8, 4.3, 1.8] - end_pose = [5.4581, 5.8064, 3.3416] - kappa = [0.5, 0, 0.5, 0] - eta = [2.98, 2.98, 0, 0, 0, 0] - path_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # construct the whole path - path = Eta3Path(path_segments) - - # interpolate at several points along the path - ui = np.linspace(0, len(path_segments), 1001) - pos = np.empty((2, ui.size)) - for i, u in enumerate(ui): - pos[:, i] = path.calc_path_point(u) - - # plot the path - - if show_animation: - plt.figure('Path from Reference') - plt.plot(pos[0, :], pos[1, :]) - plt.xlabel('x') - plt.ylabel('y') - plt.title('Path') - plt.pause(1.0) - - plt.show() - - -def main(): - """ - recreate path from reference (see Table 1) - """ - test1() - test2() - test3() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/Eta3SplineTrajectory/eta3_spline_trajectory.py b/PathPlanning/Eta3SplineTrajectory/eta3_spline_trajectory.py deleted file mode 100644 index a73797dacb9..00000000000 --- a/PathPlanning/Eta3SplineTrajectory/eta3_spline_trajectory.py +++ /dev/null @@ -1,456 +0,0 @@ -""" - -eta^3 polynomials trajectory planner - -author: Joe Dinius, Ph.D (https://jwdinius.github.io) - Atsushi Sakai (@Atsushi_twi) - -Refs: -- https://jwdinius.github.io/blog/2018/eta3traj/ -- [eta^3-Splines for the Smooth Path Generation of Wheeled Mobile Robots] -(https://ieeexplore.ieee.org/document/4339545/) - -""" - -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.collections import LineCollection -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from Eta3SplinePath.eta3_spline_path import Eta3Path, Eta3PathSegment - -show_animation = True - - -class MaxVelocityNotReached(Exception): - def __init__(self, actual_vel, max_vel): - self.message = f'Actual velocity {actual_vel} does not equal desired max velocity {max_vel}!' - - -class eta3_trajectory(Eta3Path): - """ - eta3_trajectory - - input - segments: list of `eta3_trajectory_segment` instances defining a continuous trajectory - """ - - def __init__(self, segments, max_vel, v0=0.0, a0=0.0, max_accel=2.0, max_jerk=5.0): - # ensure that all inputs obey the assumptions of the model - assert max_vel > 0 and v0 >= 0 and a0 >= 0 and max_accel > 0 and max_jerk > 0 \ - and a0 <= max_accel and v0 <= max_vel - super(__class__, self).__init__(segments=segments) - self.total_length = sum([s.segment_length for s in self.segments]) - self.max_vel = float(max_vel) - self.v0 = float(v0) - self.a0 = float(a0) - self.max_accel = float(max_accel) - self.max_jerk = float(max_jerk) - length_array = np.array([s.segment_length for s in self.segments]) - # add a zero to the beginning for finding the correct segment_id - self.cum_lengths = np.concatenate( - (np.array([0]), np.cumsum(length_array))) - # compute velocity profile on top of the path - self.velocity_profile() - self.ui_prev = 0 - self.prev_seg_id = 0 - - def velocity_profile(self): - r""" /~~~~~----------------\ - / \ - / \ - / \ - / \ - (v=v0, a=a0) ~~~~~ \ - \ - \ ~~~~~ (vf=0, af=0) - pos.|pos.|neg.| cruise at |neg.| neg. |neg. - max |max.|max.| max. |max.| max. |max. - jerk|acc.|jerk| velocity |jerk| acc. |jerk - index 0 1 2 3 (optional) 4 5 6 - """ - # delta_a: accel change from initial position to end of maximal jerk section - delta_a = self.max_accel - self.a0 - # t_s1: time of traversal of maximal jerk section - t_s1 = delta_a / self.max_jerk - # v_s1: velocity at the end of the maximal jerk section - v_s1 = self.v0 + self.a0 * t_s1 + self.max_jerk * t_s1**2 / 2. - # s_s1: length of the maximal jerk section - s_s1 = self.v0 * t_s1 + self.a0 * t_s1**2 / 2. + self.max_jerk * t_s1**3 / 6. - # t_sf: time of traversal of final section, which is also maximal jerk, but has final velocity 0 - t_sf = self.max_accel / self.max_jerk - # v_sf: velocity at beginning of final section - v_sf = self.max_jerk * t_sf**2 / 2. - # s_sf: length of final section - s_sf = self.max_jerk * t_sf**3 / 6. - # solve for the maximum achievable velocity based on the kinematic limits imposed by max_accel and max_jerk - # this leads to a quadratic equation in v_max: a*v_max**2 + b*v_max + c = 0 - a = 1 / self.max_accel - b = 3. * self.max_accel / (2. * self.max_jerk) + v_s1 / self.max_accel - ( - self.max_accel**2 / self.max_jerk + v_s1) / self.max_accel - c = s_s1 + s_sf - self.total_length - 7. * self.max_accel**3 / (3. * self.max_jerk**2) \ - - v_s1 * (self.max_accel / self.max_jerk + v_s1 / self.max_accel) \ - + (self.max_accel**2 / self.max_jerk + v_s1 / - self.max_accel)**2 / (2. * self.max_accel) - v_max = (-b + np.sqrt(b**2 - 4. * a * c)) / (2. * a) - - # v_max represents the maximum velocity that could be attained if there was no cruise period - # (i.e. driving at constant speed without accelerating or jerking) - # if this velocity is less than our desired max velocity, the max velocity needs to be updated - if self.max_vel > v_max: - # when this condition is tripped, there will be no cruise period (s_cruise=0) - self.max_vel = v_max - - # setup arrays to store values at END of trajectory sections - self.times = np.zeros((7,)) - self.vels = np.zeros((7,)) - self.seg_lengths = np.zeros((7,)) - - # Section 0: max jerk up to max acceleration - self.times[0] = t_s1 - self.vels[0] = v_s1 - self.seg_lengths[0] = s_s1 - - # Section 1: accelerate at max_accel - index = 1 - # compute change in velocity over the section - delta_v = (self.max_vel - self.max_jerk * (self.max_accel / - self.max_jerk)**2 / 2.) - self.vels[index - 1] - self.times[index] = delta_v / self.max_accel - self.vels[index] = self.vels[index - 1] + \ - self.max_accel * self.times[index] - self.seg_lengths[index] = self.vels[index - 1] * \ - self.times[index] + self.max_accel * self.times[index]**2 / 2. - - # Section 2: decrease acceleration (down to 0) until max speed is hit - index = 2 - self.times[index] = self.max_accel / self.max_jerk - self.vels[index] = self.vels[index - 1] + self.max_accel * self.times[index] \ - - self.max_jerk * self.times[index]**2 / 2. - - # as a check, the velocity at the end of the section should be self.max_vel - if not np.isclose(self.vels[index], self.max_vel): - raise MaxVelocityNotReached(self.vels[index], self.max_vel) - - self.seg_lengths[index] = self.vels[index - 1] * self.times[index] + self.max_accel * self.times[index]**2 / 2. \ - - self.max_jerk * self.times[index]**3 / 6. - - # Section 3: will be done last - - # Section 4: apply min jerk until min acceleration is hit - index = 4 - self.times[index] = self.max_accel / self.max_jerk - self.vels[index] = self.max_vel - \ - self.max_jerk * self.times[index]**2 / 2. - self.seg_lengths[index] = self.max_vel * self.times[index] - \ - self.max_jerk * self.times[index]**3 / 6. - - # Section 5: continue deceleration at max rate - index = 5 - # compute velocity change over sections - delta_v = self.vels[index - 1] - v_sf - self.times[index] = delta_v / self.max_accel - self.vels[index] = self.vels[index - 1] - \ - self.max_accel * self.times[index] - self.seg_lengths[index] = self.vels[index - 1] * \ - self.times[index] - self.max_accel * self.times[index]**2 / 2. - - # Section 6(final): max jerk to get to zero velocity and zero acceleration simultaneously - index = 6 - self.times[index] = t_sf - self.vels[index] = self.vels[index - 1] - self.max_jerk * t_sf**2 / 2. - - try: - assert np.isclose(self.vels[index], 0) - except AssertionError as e: - print(f'The final velocity {self.vels[index]} is not zero') - raise e - - self.seg_lengths[index] = s_sf - - if self.seg_lengths.sum() < self.total_length: - index = 3 - # the length of the cruise section is whatever length hasn't already been accounted for - # NOTE: the total array self.seg_lengths is summed because the entry for the cruise segment is - # initialized to 0! - self.seg_lengths[index] = self.total_length - \ - self.seg_lengths.sum() - self.vels[index] = self.max_vel - self.times[index] = self.seg_lengths[index] / self.max_vel - - # make sure that all of the times are positive, otherwise the kinematic limits - # chosen cannot be enforced on the path - assert(np.all(self.times >= 0)) - self.total_time = self.times.sum() - - def get_interp_param(self, seg_id, s, ui, tol=0.001): - def f(u): - return self.segments[seg_id].f_length(u)[0] - s - - def fprime(u): - return self.segments[seg_id].s_dot(u) - while (0 <= ui <= 1) and abs(f(ui)) > tol: - ui -= f(ui) / fprime(ui) - ui = max(0, min(ui, 1)) - return ui - - def calc_traj_point(self, time): - # compute velocity at time - if time <= self.times[0]: - linear_velocity = self.v0 + self.max_jerk * time**2 / 2. - s = self.v0 * time + self.max_jerk * time**3 / 6 - linear_accel = self.max_jerk * time - elif time <= self.times[:2].sum(): - delta_t = time - self.times[0] - linear_velocity = self.vels[0] + self.max_accel * delta_t - s = self.seg_lengths[0] + self.vels[0] * \ - delta_t + self.max_accel * delta_t**2 / 2. - linear_accel = self.max_accel - elif time <= self.times[:3].sum(): - delta_t = time - self.times[:2].sum() - linear_velocity = self.vels[1] + self.max_accel * \ - delta_t - self.max_jerk * delta_t**2 / 2. - s = self.seg_lengths[:2].sum() + self.vels[1] * delta_t + self.max_accel * delta_t**2 / 2. \ - - self.max_jerk * delta_t**3 / 6. - linear_accel = self.max_accel - self.max_jerk * delta_t - elif time <= self.times[:4].sum(): - delta_t = time - self.times[:3].sum() - linear_velocity = self.vels[3] - s = self.seg_lengths[:3].sum() + self.vels[3] * delta_t - linear_accel = 0. - elif time <= self.times[:5].sum(): - delta_t = time - self.times[:4].sum() - linear_velocity = self.vels[3] - self.max_jerk * delta_t**2 / 2. - s = self.seg_lengths[:4].sum() + self.vels[3] * \ - delta_t - self.max_jerk * delta_t**3 / 6. - linear_accel = -self.max_jerk * delta_t - elif time <= self.times[:-1].sum(): - delta_t = time - self.times[:5].sum() - linear_velocity = self.vels[4] - self.max_accel * delta_t - s = self.seg_lengths[:5].sum() + self.vels[4] * \ - delta_t - self.max_accel * delta_t**2 / 2. - linear_accel = -self.max_accel - elif time < self.times.sum(): - delta_t = time - self.times[:-1].sum() - linear_velocity = self.vels[5] - self.max_accel * \ - delta_t + self.max_jerk * delta_t**2 / 2. - s = self.seg_lengths[:-1].sum() + self.vels[5] * delta_t - self.max_accel * delta_t**2 / 2. \ - + self.max_jerk * delta_t**3 / 6. - linear_accel = -self.max_accel + self.max_jerk * delta_t - else: - linear_velocity = 0. - s = self.total_length - linear_accel = 0. - seg_id = np.max(np.argwhere(self.cum_lengths <= s)) - - # will happen at the end of the segment - if seg_id == len(self.segments): - seg_id -= 1 - ui = 1 - else: - # compute interpolation parameter using length from current segment's starting point - curr_segment_length = s - self.cum_lengths[seg_id] - ui = self.get_interp_param( - seg_id=seg_id, s=curr_segment_length, ui=self.ui_prev) - - if not seg_id == self.prev_seg_id: - self.ui_prev = 0 - else: - self.ui_prev = ui - - self.prev_seg_id = seg_id - # compute angular velocity of current point= (ydd*xd - xdd*yd) / (xd**2 + yd**2) - d = self.segments[seg_id].calc_deriv(ui, order=1) - dd = self.segments[seg_id].calc_deriv(ui, order=2) - # su - the rate of change of arclength wrt u - su = self.segments[seg_id].s_dot(ui) - if not np.isclose(su, 0.) and not np.isclose(linear_velocity, 0.): - # ut - time-derivative of interpolation parameter u - ut = linear_velocity / su - # utt - time-derivative of ut - utt = linear_accel / su - \ - (d[0] * dd[0] + d[1] * dd[1]) / su**2 * ut - xt = d[0] * ut - yt = d[1] * ut - xtt = dd[0] * ut**2 + d[0] * utt - ytt = dd[1] * ut**2 + d[1] * utt - angular_velocity = (ytt * xt - xtt * yt) / linear_velocity**2 - else: - angular_velocity = 0. - - # combine path point with orientation and velocities - pos = self.segments[seg_id].calc_point(ui) - state = np.array([pos[0], pos[1], np.arctan2( - d[1], d[0]), linear_velocity, angular_velocity]) - return state - - -def test1(max_vel=0.5): - - for i in range(10): - trajectory_segments = [] - # segment 1: lane-change curve - start_pose = [0, 0, 0] - end_pose = [4, 3.0, 0] - # NOTE: The ordering on kappa is [kappa_A, kappad_A, kappa_B, kappad_B], with kappad_* being the curvature derivative - kappa = [0, 0, 0, 0] - eta = [i, i, 0, 0, 0, 0] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - traj = eta3_trajectory(trajectory_segments, - max_vel=max_vel, max_accel=0.5) - - # interpolate at several points along the path - times = np.linspace(0, traj.total_time, 101) - state = np.empty((5, times.size)) - for j, t in enumerate(times): - state[:, j] = traj.calc_traj_point(t) - - if show_animation: # pragma: no cover - # plot the path - plt.plot(state[0, :], state[1, :]) - plt.pause(1.0) - - plt.show() - if show_animation: - plt.close("all") - - -def test2(max_vel=0.5): - - for i in range(10): - trajectory_segments = [] - # segment 1: lane-change curve - start_pose = [0, 0, 0] - end_pose = [4, 3.0, 0] - # NOTE: The ordering on kappa is [kappa_A, kappad_A, kappa_B, kappad_B], with kappad_* being the curvature derivative - kappa = [0, 0, 0, 0] - # NOTE: INTEGRATOR ERROR EXPLODES WHEN eta[:1] IS ZERO! - # was: eta = [0, 0, (i - 5) * 20, (5 - i) * 20, 0, 0], now is: - eta = [0.1, 0.1, (i - 5) * 20, (5 - i) * 20, 0, 0] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - traj = eta3_trajectory(trajectory_segments, - max_vel=max_vel, max_accel=0.5) - - # interpolate at several points along the path - times = np.linspace(0, traj.total_time, 101) - state = np.empty((5, times.size)) - for j, t in enumerate(times): - state[:, j] = traj.calc_traj_point(t) - - if show_animation: - # plot the path - plt.plot(state[0, :], state[1, :]) - plt.pause(1.0) - - plt.show() - if show_animation: - plt.close("all") - - -def test3(max_vel=2.0): - trajectory_segments = [] - - # segment 1: lane-change curve - start_pose = [0, 0, 0] - end_pose = [4, 1.5, 0] - # NOTE: The ordering on kappa is [kappa_A, kappad_A, kappa_B, kappad_B], with kappad_* being the curvature derivative - kappa = [0, 0, 0, 0] - eta = [4.27, 4.27, 0, 0, 0, 0] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 2: line segment - start_pose = [4, 1.5, 0] - end_pose = [5.5, 1.5, 0] - kappa = [0, 0, 0, 0] - # NOTE: INTEGRATOR ERROR EXPLODES WHEN eta[:1] IS ZERO! - # was: eta = [0, 0, 0, 0, 0, 0], now is: - eta = [0.5, 0.5, 0, 0, 0, 0] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 3: cubic spiral - start_pose = [5.5, 1.5, 0] - end_pose = [7.4377, 1.8235, 0.6667] - kappa = [0, 0, 1, 1] - eta = [1.88, 1.88, 0, 0, 0, 0] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 4: generic twirl arc - start_pose = [7.4377, 1.8235, 0.6667] - end_pose = [7.8, 4.3, 1.8] - kappa = [1, 1, 0.5, 0] - eta = [7, 10, 10, -10, 4, 4] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # segment 5: circular arc - start_pose = [7.8, 4.3, 1.8] - end_pose = [5.4581, 5.8064, 3.3416] - kappa = [0.5, 0, 0.5, 0] - eta = [2.98, 2.98, 0, 0, 0, 0] - trajectory_segments.append(Eta3PathSegment( - start_pose=start_pose, end_pose=end_pose, eta=eta, kappa=kappa)) - - # construct the whole path - traj = eta3_trajectory(trajectory_segments, - max_vel=max_vel, max_accel=0.5, max_jerk=1) - - # interpolate at several points along the path - times = np.linspace(0, traj.total_time, 1001) - state = np.empty((5, times.size)) - for i, t in enumerate(times): - state[:, i] = traj.calc_traj_point(t) - - # plot the path - - if show_animation: - fig, ax = plt.subplots() - x, y = state[0, :], state[1, :] - points = np.array([x, y]).T.reshape(-1, 1, 2) - segs = np.concatenate([points[:-1], points[1:]], axis=1) - lc = LineCollection(segs, cmap=plt.get_cmap('inferno')) - ax.set_xlim(np.min(x) - 1, np.max(x) + 1) - ax.set_ylim(np.min(y) - 1, np.max(y) + 1) - lc.set_array(state[3, :]) - lc.set_linewidth(3) - ax.add_collection(lc) - axcb = fig.colorbar(lc) - axcb.set_label('velocity(m/s)') - ax.set_title('Trajectory') - plt.xlabel('x') - plt.ylabel('y') - plt.pause(1.0) - - fig1, ax1 = plt.subplots() - ax1.plot(times, state[3, :], 'b-') - ax1.set_xlabel('time(s)') - ax1.set_ylabel('velocity(m/s)', color='b') - ax1.tick_params('y', colors='b') - ax1.set_title('Control') - ax2 = ax1.twinx() - ax2.plot(times, state[4, :], 'r-') - ax2.set_ylabel('angular velocity(rad/s)', color='r') - ax2.tick_params('y', colors='r') - fig.tight_layout() - plt.show() - - -def main(): - """ - recreate path from reference (see Table 1) - """ - # test1() - # test2() - test3() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/FlowField/flowfield.py b/PathPlanning/FlowField/flowfield.py deleted file mode 100644 index e50430de3c2..00000000000 --- a/PathPlanning/FlowField/flowfield.py +++ /dev/null @@ -1,227 +0,0 @@ -""" -flowfield pathfinding -author: Sarim Mehdi (muhammadsarim.mehdi@studio.unibo.it) -Source: https://leifnode.com/2013/12/flow-field-pathfinding/ -""" - -import numpy as np -import matplotlib.pyplot as plt - -show_animation = True - - -def draw_horizontal_line(start_x, start_y, length, o_x, o_y, o_dict, path): - for i in range(start_x, start_x + length): - for j in range(start_y, start_y + 2): - o_x.append(i) - o_y.append(j) - o_dict[(i, j)] = path - - -def draw_vertical_line(start_x, start_y, length, o_x, o_y, o_dict, path): - for i in range(start_x, start_x + 2): - for j in range(start_y, start_y + length): - o_x.append(i) - o_y.append(j) - o_dict[(i, j)] = path - - -class FlowField: - def __init__(self, obs_grid, goal_x, goal_y, start_x, start_y, - limit_x, limit_y): - self.start_pt = [start_x, start_y] - self.goal_pt = [goal_x, goal_y] - self.obs_grid = obs_grid - self.limit_x, self.limit_y = limit_x, limit_y - self.cost_field = {} - self.integration_field = {} - self.vector_field = {} - - def find_path(self): - self.create_cost_field() - self.create_integration_field() - self.assign_vectors() - self.follow_vectors() - - def create_cost_field(self): - """Assign cost to each grid which defines the energy - it would take to get there.""" - for i in range(self.limit_x): - for j in range(self.limit_y): - if self.obs_grid[(i, j)] == 'free': - self.cost_field[(i, j)] = 1 - elif self.obs_grid[(i, j)] == 'medium': - self.cost_field[(i, j)] = 7 - elif self.obs_grid[(i, j)] == 'hard': - self.cost_field[(i, j)] = 20 - elif self.obs_grid[(i, j)] == 'obs': - continue - - if [i, j] == self.goal_pt: - self.cost_field[(i, j)] = 0 - - def create_integration_field(self): - """Start from the goal node and calculate the value - of the integration field at each node. Start by - assigning a value of infinity to every node except - the goal node which is assigned a value of 0. Put the - goal node in the open list and then get its neighbors - (must not be obstacles). For each neighbor, the new - cost is equal to the cost of the current node in the - integration field (in the beginning, this will simply - be the goal node) + the cost of the neighbor in the - cost field + the extra cost (optional). The new cost - is only assigned if it is less than the previously - assigned cost of the node in the integration field and, - when that happens, the neighbor is put on the open list. - This process continues until the open list is empty.""" - for i in range(self.limit_x): - for j in range(self.limit_y): - if self.obs_grid[(i, j)] == 'obs': - continue - self.integration_field[(i, j)] = np.inf - if [i, j] == self.goal_pt: - self.integration_field[(i, j)] = 0 - - open_list = [(self.goal_pt, 0)] - while open_list: - curr_pos, curr_cost = open_list[0] - curr_x, curr_y = curr_pos - for i in range(-1, 2): - for j in range(-1, 2): - x, y = curr_x + i, curr_y + j - if self.obs_grid[(x, y)] == 'obs': - continue - if (i, j) in [(1, 0), (0, 1), (-1, 0), (0, -1)]: - e_cost = 10 - else: - e_cost = 14 - neighbor_energy = self.cost_field[(x, y)] - neighbor_old_cost = self.integration_field[(x, y)] - neighbor_new_cost = curr_cost + neighbor_energy + e_cost - if neighbor_new_cost < neighbor_old_cost: - self.integration_field[(x, y)] = neighbor_new_cost - open_list.append(([x, y], neighbor_new_cost)) - del open_list[0] - - def assign_vectors(self): - """For each node, assign a vector from itself to the node with - the lowest cost in the integration field. An agent will simply - follow this vector field to the goal""" - for i in range(self.limit_x): - for j in range(self.limit_y): - if self.obs_grid[(i, j)] == 'obs': - continue - if [i, j] == self.goal_pt: - self.vector_field[(i, j)] = (None, None) - continue - offset_list = [(i + a, j + b) - for a in range(-1, 2) - for b in range(-1, 2)] - neighbor_list = [{'loc': pt, - 'cost': self.integration_field[pt]} - for pt in offset_list - if self.obs_grid[pt] != 'obs'] - neighbor_list = sorted(neighbor_list, key=lambda x: x['cost']) - best_neighbor = neighbor_list[0]['loc'] - self.vector_field[(i, j)] = best_neighbor - - def follow_vectors(self): - curr_x, curr_y = self.start_pt - while curr_x is not None and curr_y is not None: - curr_x, curr_y = self.vector_field[(curr_x, curr_y)] - - if show_animation: - plt.plot(curr_x, curr_y, "b*") - plt.pause(0.001) - - if show_animation: - plt.show() - - -def main(): - # set obstacle positions - obs_dict = {} - for i in range(51): - for j in range(51): - obs_dict[(i, j)] = 'free' - o_x, o_y, m_x, m_y, h_x, h_y = [], [], [], [], [], [] - - s_x = 5.0 - s_y = 5.0 - g_x = 35.0 - g_y = 45.0 - - # draw outer border of maze - draw_vertical_line(0, 0, 50, o_x, o_y, obs_dict, 'obs') - draw_vertical_line(48, 0, 50, o_x, o_y, obs_dict, 'obs') - draw_horizontal_line(0, 0, 50, o_x, o_y, obs_dict, 'obs') - draw_horizontal_line(0, 48, 50, o_x, o_y, obs_dict, 'obs') - - # draw inner walls - all_x = [10, 10, 10, 15, 20, 20, 30, 30, 35, 30, 40, 45] - all_y = [10, 30, 45, 20, 5, 40, 10, 40, 5, 40, 10, 25] - all_len = [10, 10, 5, 10, 10, 5, 20, 10, 25, 10, 35, 15] - for x, y, l in zip(all_x, all_y, all_len): - draw_vertical_line(x, y, l, o_x, o_y, obs_dict, 'obs') - - all_x[:], all_y[:], all_len[:] = [], [], [] - all_x = [35, 40, 15, 10, 45, 20, 10, 15, 25, 45, 10, 30, 10, 40] - all_y = [5, 10, 15, 20, 20, 25, 30, 35, 35, 35, 40, 40, 45, 45] - all_len = [10, 5, 10, 10, 5, 5, 10, 5, 10, 5, 10, 5, 5, 5] - for x, y, l in zip(all_x, all_y, all_len): - draw_horizontal_line(x, y, l, o_x, o_y, obs_dict, 'obs') - - # Some points are assigned a slightly higher energy value in the cost - # field. For example, if an agent wishes to go to a point, it might - # encounter different kind of terrain like grass and dirt. Grass is - # assigned medium difficulty of passage (color coded as green on the - # map here). Dirt is assigned hard difficulty of passage (color coded - # as brown here). Hence, this algorithm will take into account how - # difficult it is to go through certain areas of a map when deciding - # the shortest path. - - # draw paths that have medium difficulty (in terms of going through them) - all_x[:], all_y[:], all_len[:] = [], [], [] - all_x = [10, 45] - all_y = [22, 20] - all_len = [8, 5] - for x, y, l in zip(all_x, all_y, all_len): - draw_vertical_line(x, y, l, m_x, m_y, obs_dict, 'medium') - - all_x[:], all_y[:], all_len[:] = [], [], [] - all_x = [20, 30, 42] + [47] * 5 - all_y = [35, 30, 38] + [37 + i for i in range(2)] - all_len = [5, 7, 3] + [1] * 3 - for x, y, l in zip(all_x, all_y, all_len): - draw_horizontal_line(x, y, l, m_x, m_y, obs_dict, 'medium') - - # draw paths that have hard difficulty (in terms of going through them) - all_x[:], all_y[:], all_len[:] = [], [], [] - all_x = [15, 20, 35] - all_y = [45, 20, 35] - all_len = [3, 5, 7] - for x, y, l in zip(all_x, all_y, all_len): - draw_vertical_line(x, y, l, h_x, h_y, obs_dict, 'hard') - - all_x[:], all_y[:], all_len[:] = [], [], [] - all_x = [30] + [47] * 5 - all_y = [10] + [37 + i for i in range(2)] - all_len = [5] + [1] * 3 - for x, y, l in zip(all_x, all_y, all_len): - draw_horizontal_line(x, y, l, h_x, h_y, obs_dict, 'hard') - - if show_animation: - plt.plot(o_x, o_y, "sr") - plt.plot(m_x, m_y, "sg") - plt.plot(h_x, h_y, "sy") - plt.plot(s_x, s_y, "og") - plt.plot(g_x, g_y, "o") - plt.grid(True) - - flow_obj = FlowField(obs_dict, g_x, g_y, s_x, s_y, 50, 50) - flow_obj.find_path() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/FrenetOptimalTrajectory/cartesian_frenet_converter.py b/PathPlanning/FrenetOptimalTrajectory/cartesian_frenet_converter.py deleted file mode 100644 index 4cc8650c89a..00000000000 --- a/PathPlanning/FrenetOptimalTrajectory/cartesian_frenet_converter.py +++ /dev/null @@ -1,144 +0,0 @@ -""" - -A converter between Cartesian and Frenet coordinate systems - -author: Wang Zheng (@Aglargil) - -Ref: - -- [Optimal Trajectory Generation for Dynamic Street Scenarios in a Frenet Frame] -(https://www.researchgate.net/profile/Moritz_Werling/publication/224156269_Optimal_Trajectory_Generation_for_Dynamic_Street_Scenarios_in_a_Frenet_Frame/links/54f749df0cf210398e9277af.pdf) - -""" - -import math - - -class CartesianFrenetConverter: - """ - A class for converting states between Cartesian and Frenet coordinate systems - """ - - @ staticmethod - def cartesian_to_frenet(rs, rx, ry, rtheta, rkappa, rdkappa, x, y, v, a, theta, kappa): - """ - Convert state from Cartesian coordinate to Frenet coordinate - - Parameters - ---------- - rs: reference line s-coordinate - rx, ry: reference point coordinates - rtheta: reference point heading - rkappa: reference point curvature - rdkappa: reference point curvature rate - x, y: current position - v: velocity - a: acceleration - theta: heading angle - kappa: curvature - - Returns - ------- - s_condition: [s(t), s'(t), s''(t)] - d_condition: [d(s), d'(s), d''(s)] - """ - dx = x - rx - dy = y - ry - - cos_theta_r = math.cos(rtheta) - sin_theta_r = math.sin(rtheta) - - cross_rd_nd = cos_theta_r * dy - sin_theta_r * dx - d = math.copysign(math.hypot(dx, dy), cross_rd_nd) - - delta_theta = theta - rtheta - tan_delta_theta = math.tan(delta_theta) - cos_delta_theta = math.cos(delta_theta) - - one_minus_kappa_r_d = 1 - rkappa * d - d_dot = one_minus_kappa_r_d * tan_delta_theta - - kappa_r_d_prime = rdkappa * d + rkappa * d_dot - - d_ddot = (-kappa_r_d_prime * tan_delta_theta + - one_minus_kappa_r_d / (cos_delta_theta * cos_delta_theta) * - (kappa * one_minus_kappa_r_d / cos_delta_theta - rkappa)) - - s = rs - s_dot = v * cos_delta_theta / one_minus_kappa_r_d - - delta_theta_prime = one_minus_kappa_r_d / cos_delta_theta * kappa - rkappa - s_ddot = (a * cos_delta_theta - - s_dot * s_dot * - (d_dot * delta_theta_prime - kappa_r_d_prime)) / one_minus_kappa_r_d - - return [s, s_dot, s_ddot], [d, d_dot, d_ddot] - - @ staticmethod - def frenet_to_cartesian(rs, rx, ry, rtheta, rkappa, rdkappa, s_condition, d_condition): - """ - Convert state from Frenet coordinate to Cartesian coordinate - - Parameters - ---------- - rs: reference line s-coordinate - rx, ry: reference point coordinates - rtheta: reference point heading - rkappa: reference point curvature - rdkappa: reference point curvature rate - s_condition: [s(t), s'(t), s''(t)] - d_condition: [d(s), d'(s), d''(s)] - - Returns - ------- - x, y: position - theta: heading angle - kappa: curvature - v: velocity - a: acceleration - """ - if abs(rs - s_condition[0]) >= 1.0e-6: - raise ValueError( - "The reference point s and s_condition[0] don't match") - - cos_theta_r = math.cos(rtheta) - sin_theta_r = math.sin(rtheta) - - x = rx - sin_theta_r * d_condition[0] - y = ry + cos_theta_r * d_condition[0] - - one_minus_kappa_r_d = 1 - rkappa * d_condition[0] - - tan_delta_theta = d_condition[1] / one_minus_kappa_r_d - delta_theta = math.atan2(d_condition[1], one_minus_kappa_r_d) - cos_delta_theta = math.cos(delta_theta) - - theta = CartesianFrenetConverter.normalize_angle(delta_theta + rtheta) - - kappa_r_d_prime = rdkappa * d_condition[0] + rkappa * d_condition[1] - - kappa = (((d_condition[2] + kappa_r_d_prime * tan_delta_theta) * - cos_delta_theta * cos_delta_theta) / one_minus_kappa_r_d + rkappa) * \ - cos_delta_theta / one_minus_kappa_r_d - - d_dot = d_condition[1] * s_condition[1] - v = math.sqrt(one_minus_kappa_r_d * one_minus_kappa_r_d * - s_condition[1] * s_condition[1] + d_dot * d_dot) - - delta_theta_prime = one_minus_kappa_r_d / cos_delta_theta * kappa - rkappa - - a = (s_condition[2] * one_minus_kappa_r_d / cos_delta_theta + - s_condition[1] * s_condition[1] / cos_delta_theta * - (d_condition[1] * delta_theta_prime - kappa_r_d_prime)) - - return x, y, theta, kappa, v, a - - @ staticmethod - def normalize_angle(angle): - """ - Normalize angle to [-pi, pi] - """ - a = math.fmod(angle + math.pi, 2.0 * math.pi) - if a < 0.0: - a += 2.0 * math.pi - return a - math.pi diff --git a/PathPlanning/FrenetOptimalTrajectory/frenet_optimal_trajectory.py b/PathPlanning/FrenetOptimalTrajectory/frenet_optimal_trajectory.py deleted file mode 100644 index 248894c1c60..00000000000 --- a/PathPlanning/FrenetOptimalTrajectory/frenet_optimal_trajectory.py +++ /dev/null @@ -1,568 +0,0 @@ -""" - -Frenet optimal trajectory generator - -author: Atsushi Sakai (@Atsushi_twi) - -Ref: - -- [Optimal Trajectory Generation for Dynamic Street Scenarios in a Frenet Frame] -(https://www.researchgate.net/profile/Moritz_Werling/publication/224156269_Optimal_Trajectory_Generation_for_Dynamic_Street_Scenarios_in_a_Frenet_Frame/links/54f749df0cf210398e9277af.pdf) - -- [Optimal trajectory generation for dynamic street scenarios in a Frenet Frame] -(https://www.youtube.com/watch?v=Cj6tAQe7UCY) - -""" - -import numpy as np -import matplotlib.pyplot as plt -import copy -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from QuinticPolynomialsPlanner.quintic_polynomials_planner import QuinticPolynomial -from CubicSpline import cubic_spline_planner - -from enum import Enum, auto -from FrenetOptimalTrajectory.cartesian_frenet_converter import ( - CartesianFrenetConverter, -) - - -class LateralMovement(Enum): - HIGH_SPEED = auto() - LOW_SPEED = auto() - - -class LongitudinalMovement(Enum): - MERGING_AND_STOPPING = auto() - VELOCITY_KEEPING = auto() - - -# Default Parameters - -LATERAL_MOVEMENT = LateralMovement.HIGH_SPEED -LONGITUDINAL_MOVEMENT = LongitudinalMovement.VELOCITY_KEEPING - -MAX_SPEED = 50.0 / 3.6 # maximum speed [m/s] -MAX_ACCEL = 5.0 # maximum acceleration [m/ss] -MAX_CURVATURE = 1.0 # maximum curvature [1/m] -DT = 0.2 # time tick [s] -MAX_T = 5.0 # max prediction time [m] -MIN_T = 4.0 # min prediction time [m] -N_S_SAMPLE = 1 # sampling number of target speed - -# cost weights -K_J = 0.1 -K_T = 0.1 -K_S_DOT = 1.0 -K_D = 1.0 -K_S = 1.0 -K_LAT = 1.0 -K_LON = 1.0 - -SIM_LOOP = 500 -show_animation = True - - -if LATERAL_MOVEMENT == LateralMovement.LOW_SPEED: - MAX_ROAD_WIDTH = 1.0 # maximum road width [m] - D_ROAD_W = 0.2 # road width sampling length [m] - TARGET_SPEED = 3.0 / 3.6 # maximum speed [m/s] - D_T_S = 0.5 / 3.6 # target speed sampling length [m/s] - # Waypoints - WX = [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] - WY = [0.0, 0.0, 1.0, 0.0, -1.0, -2.0] - OBSTACLES = np.array([[3.0, 1.0], [5.0, -0.0], [6.0, 0.5], [8.0, -1.5]]) - ROBOT_RADIUS = 0.5 # robot radius [m] - - # Initial state parameters - INITIAL_SPEED = 1.0 / 3.6 # current speed [m/s] - INITIAL_ACCEL = 0.0 # current acceleration [m/ss] - INITIAL_LAT_POSITION = 0.5 # current lateral position [m] - INITIAL_LAT_SPEED = 0.0 # current lateral speed [m/s] - INITIAL_LAT_ACCELERATION = 0.0 # current lateral acceleration [m/s] - INITIAL_COURSE_POSITION = 0.0 # current course position - - ANIMATION_AREA = 5.0 # Animation area length [m] - - STOP_S = 4.0 # Merge and stop distance [m] - D_S = 0.3 # Stop point sampling length [m] - N_STOP_S_SAMPLE = 3 # Stop point sampling number -else: - MAX_ROAD_WIDTH = 7.0 # maximum road width [m] - D_ROAD_W = 1.0 # road width sampling length [m] - TARGET_SPEED = 30.0 / 3.6 # target speed [m/s] - D_T_S = 5.0 / 3.6 # target speed sampling length [m/s] - # Waypoints - WX = [0.0, 10.0, 20.5, 35.0, 70.5] - WY = [0.0, -6.0, 5.0, 6.5, 0.0] - # Obstacle list - OBSTACLES = np.array( - [[20.0, 10.0], [30.0, 6.0], [30.0, 8.0], [35.0, 8.0], [50.0, 3.0]] - ) - ROBOT_RADIUS = 2.0 # robot radius [m] - - # Initial state parameters - INITIAL_SPEED = 10.0 / 3.6 # current speed [m/s] - INITIAL_ACCEL = 0.0 # current acceleration [m/ss] - INITIAL_LAT_POSITION = 2.0 # current lateral position [m] - INITIAL_LAT_SPEED = 0.0 # current lateral speed [m/s] - INITIAL_LAT_ACCELERATION = 0.0 # current lateral acceleration [m/s] - INITIAL_COURSE_POSITION = 0.0 # current course position - - ANIMATION_AREA = 20.0 # Animation area length [m] - STOP_S = 25.0 # Merge and stop distance [m] - D_S = 2 # Stop point sampling length [m] - N_STOP_S_SAMPLE = 4 # Stop point sampling number - - -class LateralMovementStrategy: - def calc_lateral_trajectory(self, fp, di, c_d, c_d_d, c_d_dd, Ti): - """ - Calculate the lateral trajectory - """ - raise NotImplementedError("calc_lateral_trajectory not implemented") - - def calc_cartesian_parameters(self, fp, csp): - """ - Calculate the cartesian parameters (x, y, yaw, curvature, v, a) - """ - raise NotImplementedError("calc_cartesian_parameters not implemented") - - -class HighSpeedLateralMovementStrategy(LateralMovementStrategy): - def calc_lateral_trajectory(self, fp, di, c_d, c_d_d, c_d_dd, Ti): - tp = copy.deepcopy(fp) - s0_d = fp.s_d[0] - s0_dd = fp.s_dd[0] - # d'(t) = d'(s) * s'(t) - # d''(t) = d''(s) * s'(t)^2 + d'(s) * s''(t) - lat_qp = QuinticPolynomial( - c_d, c_d_d * s0_d, c_d_dd * s0_d**2 + c_d_d * s0_dd, di, 0.0, 0.0, Ti - ) - - tp.d = [] - tp.d_d = [] - tp.d_dd = [] - tp.d_ddd = [] - - # Calculate all derivatives in a single loop to reduce iterations - for i in range(len(fp.t)): - t = fp.t[i] - s_d = fp.s_d[i] - s_dd = fp.s_dd[i] - - s_d_inv = 1.0 / (s_d + 1e-6) + 1e-6 # Avoid division by zero - s_d_inv_sq = s_d_inv * s_d_inv # Square of inverse - - d = lat_qp.calc_point(t) - d_d = lat_qp.calc_first_derivative(t) - d_dd = lat_qp.calc_second_derivative(t) - d_ddd = lat_qp.calc_third_derivative(t) - - tp.d.append(d) - # d'(s) = d'(t) / s'(t) - tp.d_d.append(d_d * s_d_inv) - # d''(s) = (d''(t) - d'(s) * s''(t)) / s'(t)^2 - tp.d_dd.append((d_dd - tp.d_d[i] * s_dd) * s_d_inv_sq) - tp.d_ddd.append(d_ddd) - - return tp - - def calc_cartesian_parameters(self, fp, csp): - # calc global positions - for i in range(len(fp.s)): - ix, iy = csp.calc_position(fp.s[i]) - if ix is None: - break - i_yaw = csp.calc_yaw(fp.s[i]) - i_kappa = csp.calc_curvature(fp.s[i]) - i_dkappa = csp.calc_curvature_rate(fp.s[i]) - s_condition = [fp.s[i], fp.s_d[i], fp.s_dd[i]] - d_condition = [ - fp.d[i], - fp.d_d[i], - fp.d_dd[i], - ] - x, y, theta, kappa, v, a = CartesianFrenetConverter.frenet_to_cartesian( - fp.s[i], ix, iy, i_yaw, i_kappa, i_dkappa, s_condition, d_condition - ) - fp.x.append(x) - fp.y.append(y) - fp.yaw.append(theta) - fp.c.append(kappa) - fp.v.append(v) - fp.a.append(a) - return fp - - -class LowSpeedLateralMovementStrategy(LateralMovementStrategy): - def calc_lateral_trajectory(self, fp, di, c_d, c_d_d, c_d_dd, Ti): - s0 = fp.s[0] - s1 = fp.s[-1] - tp = copy.deepcopy(fp) - # d = d(s), d_d = d'(s), d_dd = d''(s) - # * shift s range from [s0, s1] to [0, s1 - s0] - lat_qp = QuinticPolynomial(c_d, c_d_d, c_d_dd, di, 0.0, 0.0, s1 - s0) - - tp.d = [lat_qp.calc_point(s - s0) for s in fp.s] - tp.d_d = [lat_qp.calc_first_derivative(s - s0) for s in fp.s] - tp.d_dd = [lat_qp.calc_second_derivative(s - s0) for s in fp.s] - tp.d_ddd = [lat_qp.calc_third_derivative(s - s0) for s in fp.s] - return tp - - def calc_cartesian_parameters(self, fp, csp): - # calc global positions - for i in range(len(fp.s)): - ix, iy = csp.calc_position(fp.s[i]) - if ix is None: - break - i_yaw = csp.calc_yaw(fp.s[i]) - i_kappa = csp.calc_curvature(fp.s[i]) - i_dkappa = csp.calc_curvature_rate(fp.s[i]) - s_condition = [fp.s[i], fp.s_d[i], fp.s_dd[i]] - d_condition = [fp.d[i], fp.d_d[i], fp.d_dd[i]] - x, y, theta, kappa, v, a = CartesianFrenetConverter.frenet_to_cartesian( - fp.s[i], ix, iy, i_yaw, i_kappa, i_dkappa, s_condition, d_condition - ) - fp.x.append(x) - fp.y.append(y) - fp.yaw.append(theta) - fp.c.append(kappa) - fp.v.append(v) - fp.a.append(a) - return fp - - -class LongitudinalMovementStrategy: - def calc_longitudinal_trajectory(self, c_speed, c_accel, Ti, s0): - """ - Calculate the longitudinal trajectory - """ - raise NotImplementedError("calc_longitudinal_trajectory not implemented") - - def get_d_arrange(self, s0): - """ - Get the d sample range - """ - raise NotImplementedError("get_d_arrange not implemented") - - def calc_destination_cost(self, fp): - """ - Calculate the destination cost - """ - raise NotImplementedError("calc_destination_cost not implemented") - - -class VelocityKeepingLongitudinalMovementStrategy(LongitudinalMovementStrategy): - def calc_longitudinal_trajectory(self, c_speed, c_accel, Ti, s0): - fplist = [] - for tv in np.arange( - TARGET_SPEED - D_T_S * N_S_SAMPLE, TARGET_SPEED + D_T_S * N_S_SAMPLE, D_T_S - ): - fp = FrenetPath() - lon_qp = QuarticPolynomial(s0, c_speed, c_accel, tv, 0.0, Ti) - fp.t = [t for t in np.arange(0.0, Ti, DT)] - fp.s = [lon_qp.calc_point(t) for t in fp.t] - fp.s_d = [lon_qp.calc_first_derivative(t) for t in fp.t] - fp.s_dd = [lon_qp.calc_second_derivative(t) for t in fp.t] - fp.s_ddd = [lon_qp.calc_third_derivative(t) for t in fp.t] - fplist.append(fp) - return fplist - - def get_d_arrange(self, s0): - return np.arange(-MAX_ROAD_WIDTH, MAX_ROAD_WIDTH, D_ROAD_W) - - def calc_destination_cost(self, fp): - ds = (TARGET_SPEED - fp.s_d[-1]) ** 2 - return K_S_DOT * ds - - -class MergingAndStoppingLongitudinalMovementStrategy(LongitudinalMovementStrategy): - def calc_longitudinal_trajectory(self, c_speed, c_accel, Ti, s0): - if s0 >= STOP_S: - return [] - fplist = [] - for s in np.arange( - STOP_S - D_S * N_STOP_S_SAMPLE, STOP_S + D_S * N_STOP_S_SAMPLE, D_S - ): - fp = FrenetPath() - lon_qp = QuinticPolynomial(s0, c_speed, c_accel, s, 0.0, 0.0, Ti) - fp.t = [t for t in np.arange(0.0, Ti, DT)] - fp.s = [lon_qp.calc_point(t) for t in fp.t] - fp.s_d = [lon_qp.calc_first_derivative(t) for t in fp.t] - fp.s_dd = [lon_qp.calc_second_derivative(t) for t in fp.t] - fp.s_ddd = [lon_qp.calc_third_derivative(t) for t in fp.t] - fplist.append(fp) - return fplist - - def get_d_arrange(self, s0): - # Only if s0 is less than STOP_S / 3, then we sample the road width - if s0 < STOP_S / 3: - return np.arange(-MAX_ROAD_WIDTH, MAX_ROAD_WIDTH, D_ROAD_W) - else: - return [0.0] - - def calc_destination_cost(self, fp): - ds = (STOP_S - fp.s[-1]) ** 2 - return K_S * ds - -LATERAL_MOVEMENT_STRATEGY: LateralMovementStrategy -LONGITUDINAL_MOVEMENT_STRATEGY: LongitudinalMovementStrategy - -if LATERAL_MOVEMENT == LateralMovement.HIGH_SPEED: - LATERAL_MOVEMENT_STRATEGY = HighSpeedLateralMovementStrategy() -else: - LATERAL_MOVEMENT_STRATEGY = LowSpeedLateralMovementStrategy() - -if LONGITUDINAL_MOVEMENT == LongitudinalMovement.VELOCITY_KEEPING: - LONGITUDINAL_MOVEMENT_STRATEGY = VelocityKeepingLongitudinalMovementStrategy() -else: - LONGITUDINAL_MOVEMENT_STRATEGY = MergingAndStoppingLongitudinalMovementStrategy() - - -class QuarticPolynomial: - def __init__(self, xs, vxs, axs, vxe, axe, time): - # calc coefficient of quartic polynomial - - self.a0 = xs - self.a1 = vxs - self.a2 = axs / 2.0 - - A = np.array([[3 * time**2, 4 * time**3], [6 * time, 12 * time**2]]) - b = np.array([vxe - self.a1 - 2 * self.a2 * time, axe - 2 * self.a2]) - x = np.linalg.solve(A, b) - - self.a3 = x[0] - self.a4 = x[1] - - def calc_point(self, t): - xt = self.a0 + self.a1 * t + self.a2 * t**2 + self.a3 * t**3 + self.a4 * t**4 - - return xt - - def calc_first_derivative(self, t): - xt = self.a1 + 2 * self.a2 * t + 3 * self.a3 * t**2 + 4 * self.a4 * t**3 - - return xt - - def calc_second_derivative(self, t): - xt = 2 * self.a2 + 6 * self.a3 * t + 12 * self.a4 * t**2 - - return xt - - def calc_third_derivative(self, t): - xt = 6 * self.a3 + 24 * self.a4 * t - - return xt - - -class FrenetPath: - def __init__(self): - self.t = [] - self.d = [] - self.d_d = [] # d'(s) - self.d_dd = [] # d''(s) - self.d_ddd = [] # d'''(t) in low speed / d'''(s) in high speed - self.s = [] - self.s_d = [] # s'(t) - self.s_dd = [] # s''(t) - self.s_ddd = [] # s'''(t) - self.cf = 0.0 - - self.x = [] - self.y = [] - self.yaw = [] - self.v = [] - self.a = [] - self.ds = [] - self.c = [] - - def pop_front(self): - self.x.pop(0) - self.y.pop(0) - self.yaw.pop(0) - self.v.pop(0) - self.a.pop(0) - self.s.pop(0) - self.s_d.pop(0) - self.s_dd.pop(0) - self.s_ddd.pop(0) - self.d.pop(0) - self.d_d.pop(0) - self.d_dd.pop(0) - self.d_ddd.pop(0) - - -def calc_frenet_paths(c_s_d, c_s_dd, c_d, c_d_d, c_d_dd, s0): - frenet_paths = [] - - for Ti in np.arange(MIN_T, MAX_T, DT): - lon_paths = LONGITUDINAL_MOVEMENT_STRATEGY.calc_longitudinal_trajectory( - c_s_d, c_s_dd, Ti, s0 - ) - - for fp in lon_paths: - for di in LONGITUDINAL_MOVEMENT_STRATEGY.get_d_arrange(s0): - tp = LATERAL_MOVEMENT_STRATEGY.calc_lateral_trajectory( - fp, di, c_d, c_d_d, c_d_dd, Ti - ) - - Jp = sum(np.power(tp.d_ddd, 2)) # square of jerk - Js = sum(np.power(tp.s_ddd, 2)) # square of jerk - - lat_cost = K_J * Jp + K_T * Ti + K_D * tp.d[-1] ** 2 - lon_cost = ( - K_J * Js - + K_T * Ti - + LONGITUDINAL_MOVEMENT_STRATEGY.calc_destination_cost(tp) - ) - tp.cf = K_LAT * lat_cost + K_LON * lon_cost - frenet_paths.append(tp) - - return frenet_paths - - -def calc_global_paths(fplist, csp): - return [ - LATERAL_MOVEMENT_STRATEGY.calc_cartesian_parameters(fp, csp) for fp in fplist - ] - - -def check_collision(fp, ob): - for i in range(len(ob[:, 0])): - d = [ - ((ix - ob[i, 0]) ** 2 + (iy - ob[i, 1]) ** 2) - for (ix, iy) in zip(fp.x, fp.y) - ] - - collision = any([di <= ROBOT_RADIUS**2 for di in d]) - - if collision: - return False - - return True - - -def check_paths(fplist, ob): - path_dict = { - "max_speed_error": [], - "max_accel_error": [], - "max_curvature_error": [], - "collision_error": [], - "ok": [], - } - for i, _ in enumerate(fplist): - if any([v > MAX_SPEED for v in fplist[i].v]): # Max speed check - path_dict["max_speed_error"].append(fplist[i]) - elif any([abs(a) > MAX_ACCEL for a in fplist[i].a]): # Max accel check - path_dict["max_accel_error"].append(fplist[i]) - elif any([abs(c) > MAX_CURVATURE for c in fplist[i].c]): # Max curvature check - path_dict["max_curvature_error"].append(fplist[i]) - elif not check_collision(fplist[i], ob): - path_dict["collision_error"].append(fplist[i]) - else: - path_dict["ok"].append(fplist[i]) - return path_dict - - -def frenet_optimal_planning(csp, s0, c_s_d, c_s_dd, c_d, c_d_d, c_d_dd, ob): - fplist = calc_frenet_paths(c_s_d, c_s_dd, c_d, c_d_d, c_d_dd, s0) - fplist = calc_global_paths(fplist, csp) - fpdict = check_paths(fplist, ob) - - # find minimum cost path - min_cost = float("inf") - best_path = None - for fp in fpdict["ok"]: - if min_cost >= fp.cf: - min_cost = fp.cf - best_path = fp - - return [best_path, fpdict] - - -def generate_target_course(x, y): - csp = cubic_spline_planner.CubicSpline2D(x, y) - s = np.arange(0, csp.s[-1], 0.1) - - rx, ry, ryaw, rk = [], [], [], [] - for i_s in s: - ix, iy = csp.calc_position(i_s) - rx.append(ix) - ry.append(iy) - ryaw.append(csp.calc_yaw(i_s)) - rk.append(csp.calc_curvature(i_s)) - - return rx, ry, ryaw, rk, csp - - -def main(): - print(__file__ + " start!!") - - tx, ty, tyaw, tc, csp = generate_target_course(WX, WY) - - # Initialize state using global parameters - c_s_d = INITIAL_SPEED - c_s_dd = INITIAL_ACCEL - c_d = INITIAL_LAT_POSITION - c_d_d = INITIAL_LAT_SPEED - c_d_dd = INITIAL_LAT_ACCELERATION - s0 = INITIAL_COURSE_POSITION - - area = ANIMATION_AREA - - last_path = None - - for i in range(SIM_LOOP): - [path, fpdict] = frenet_optimal_planning( - csp, s0, c_s_d, c_s_dd, c_d, c_d_d, c_d_dd, OBSTACLES - ) - - if path is None: - path = copy.deepcopy(last_path) - path.pop_front() - if len(path.x) <= 1: - print("Finish") - break - - last_path = path - s0 = path.s[1] - c_d = path.d[1] - c_d_d = path.d_d[1] - c_d_dd = path.d_dd[1] - c_s_d = path.s_d[1] - c_s_dd = path.s_dd[1] - if np.hypot(path.x[1] - tx[-1], path.y[1] - ty[-1]) <= 1.0: - print("Goal") - break - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - "key_release_event", - lambda event: [exit(0) if event.key == "escape" else None], - ) - plt.plot(tx, ty) - plt.plot(OBSTACLES[:, 0], OBSTACLES[:, 1], "xk") - plt.plot(path.x[1:], path.y[1:], "-or") - plt.plot(path.x[1], path.y[1], "vc") - plt.xlim(path.x[1] - area, path.x[1] + area) - plt.ylim(path.y[1] - area, path.y[1] + area) - plt.title("v[km/h]:" + str(path.v[1] * 3.6)[0:4]) - plt.grid(True) - plt.pause(0.0001) - - print("Finish") - if show_animation: # pragma: no cover - plt.grid(True) - plt.pause(0.0001) - plt.show() - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/GreedyBestFirstSearch/greedy_best_first_search.py b/PathPlanning/GreedyBestFirstSearch/greedy_best_first_search.py deleted file mode 100644 index b259beb8700..00000000000 --- a/PathPlanning/GreedyBestFirstSearch/greedy_best_first_search.py +++ /dev/null @@ -1,278 +0,0 @@ -""" - -Greedy Best-First grid planning - -author: Erwin Lejeune (@spida_rwin) - -See Wikipedia article (https://en.wikipedia.org/wiki/Best-first_search) - -""" - -import math - -import matplotlib.pyplot as plt - -show_animation = True - - -class BestFirstSearchPlanner: - - def __init__(self, ox, oy, reso, rr): - """ - Initialize grid map for greedy best-first planning - - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - self.reso = reso - self.rr = rr - self.calc_obstacle_map(ox, oy) - self.motion = self.get_motion_model() - - class Node: - def __init__(self, x, y, cost, pind, parent): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.pind = pind - self.parent = parent - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.pind) - - def planning(self, sx, sy, gx, gy): - """ - Greedy Best-First search - - input: - s_x: start x position [m] - s_y: start y position [m] - gx: goal x position [m] - gy: goal y position [m] - - output: - rx: x position list of the final path - ry: y position list of the final path - """ - - nstart = self.Node(self.calc_xyindex(sx, self.minx), - self.calc_xyindex(sy, self.miny), 0.0, -1, None) - ngoal = self.Node(self.calc_xyindex(gx, self.minx), - self.calc_xyindex(gy, self.miny), 0.0, -1, None) - - open_set, closed_set = dict(), dict() - open_set[self.calc_grid_index(nstart)] = nstart - - while True: - if len(open_set) == 0: - print("Open set is empty..") - break - - c_id = min( - open_set, - key=lambda o: self.calc_heuristic(ngoal, open_set[o])) - - current = open_set[c_id] - - # show graph - if show_animation: # pragma: no cover - plt.plot(self.calc_grid_position(current.x, self.minx), - self.calc_grid_position(current.y, self.miny), "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: - [exit(0) - if event.key == 'escape' - else None]) - if len(closed_set.keys()) % 10 == 0: - plt.pause(0.001) - - # Remove the item from the open set - del open_set[c_id] - - # Add it to the closed set - closed_set[c_id] = current - - if current.x == ngoal.x and current.y == ngoal.y: - print("Found goal") - ngoal.pind = current.pind - ngoal.cost = current.cost - break - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - node = self.Node(current.x + self.motion[i][0], - current.y + self.motion[i][1], - current.cost + self.motion[i][2], - c_id, current) - - n_id = self.calc_grid_index(node) - - # If the node is not safe, do nothing - if not self.verify_node(node): - continue - - if n_id in closed_set: - continue - - if n_id not in open_set: - open_set[n_id] = node - else: - if open_set[n_id].cost > node.cost: - open_set[n_id] = node - closed_set[ngoal.pind] = current - rx, ry = self.calc_final_path(ngoal, closed_set) - return rx, ry - - def calc_final_path(self, ngoal, closedset): - # generate final course - rx, ry = [self.calc_grid_position(ngoal.x, self.minx)], [ - self.calc_grid_position(ngoal.y, self.miny)] - n = closedset[ngoal.pind] - while n is not None: - rx.append(self.calc_grid_position(n.x, self.minx)) - ry.append(self.calc_grid_position(n.y, self.miny)) - n = n.parent - - return rx, ry - - @staticmethod - def calc_heuristic(n1, n2): - w = 1.0 # weight of heuristic - d = w * math.hypot(n1.x - n2.x, n1.y - n2.y) - return d - - def calc_grid_position(self, index, minp): - """ - calc grid position - - :param index: - :param minp: - :return: - """ - pos = index * self.reso + minp - return pos - - def calc_xyindex(self, position, min_pos): - return round((position - min_pos) / self.reso) - - def calc_grid_index(self, node): - return (node.y - self.miny) * self.xwidth + (node.x - self.minx) - - def verify_node(self, node): - px = self.calc_grid_position(node.x, self.minx) - py = self.calc_grid_position(node.y, self.miny) - - if px < self.minx: - return False - elif py < self.miny: - return False - elif px >= self.maxx: - return False - elif py >= self.maxy: - return False - - # collision check - if self.obmap[node.x][node.y]: - return False - - return True - - def calc_obstacle_map(self, ox, oy): - - self.minx = round(min(ox)) - self.miny = round(min(oy)) - self.maxx = round(max(ox)) - self.maxy = round(max(oy)) - print("min_x:", self.minx) - print("min_y:", self.miny) - print("max_x:", self.maxx) - print("max_y:", self.maxy) - - self.xwidth = round((self.maxx - self.minx) / self.reso) - self.ywidth = round((self.maxy - self.miny) / self.reso) - print("x_width:", self.xwidth) - print("y_width:", self.ywidth) - - # obstacle map generation - self.obmap = [[False for _ in range(self.ywidth)] - for _ in range(self.xwidth)] - for ix in range(self.xwidth): - x = self.calc_grid_position(ix, self.minx) - for iy in range(self.ywidth): - y = self.calc_grid_position(iy, self.miny) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= self.rr: - self.obmap[ix][iy] = True - break - - @staticmethod - 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 - - -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 = 2.0 # [m] - robot_radius = 1.0 # [m] - - # set obstacle positions - ox, oy = [], [] - for i in range(-10, 60): - ox.append(i) - oy.append(-10.0) - for i in range(-10, 60): - ox.append(60.0) - oy.append(i) - for i in range(-10, 61): - ox.append(i) - oy.append(60.0) - for i in range(-10, 61): - ox.append(-10.0) - oy.append(i) - for i in range(-10, 40): - ox.append(20.0) - oy.append(i) - for i in range(0, 40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "og") - plt.plot(gx, gy, "xb") - plt.grid(True) - plt.axis("equal") - - greedybestfirst = BestFirstSearchPlanner(ox, oy, grid_size, robot_radius) - rx, ry = greedybestfirst.planning(sx, sy, gx, gy) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.01) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/GridBasedSweepCPP/grid_based_sweep_coverage_path_planner.py b/PathPlanning/GridBasedSweepCPP/grid_based_sweep_coverage_path_planner.py deleted file mode 100644 index 10ba98cd352..00000000000 --- a/PathPlanning/GridBasedSweepCPP/grid_based_sweep_coverage_path_planner.py +++ /dev/null @@ -1,321 +0,0 @@ -""" -Grid based sweep planner - -author: Atsushi Sakai -""" - -import math -from enum import IntEnum -import numpy as np -import matplotlib.pyplot as plt -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -from utils.angle import rot_mat_2d -from Mapping.grid_map_lib.grid_map_lib import GridMap, FloatGrid - -do_animation = True - - -class SweepSearcher: - class SweepDirection(IntEnum): - UP = 1 - DOWN = -1 - - class MovingDirection(IntEnum): - RIGHT = 1 - LEFT = -1 - - def __init__(self, - moving_direction, sweep_direction, x_inds_goal_y, goal_y): - self.moving_direction = moving_direction - self.sweep_direction = sweep_direction - self.turing_window = [] - self.update_turning_window() - self.x_indexes_goal_y = x_inds_goal_y - self.goal_y = goal_y - - def move_target_grid(self, c_x_index, c_y_index, grid_map): - n_x_index = self.moving_direction + c_x_index - n_y_index = c_y_index - - # found safe grid - if not self.check_occupied(n_x_index, n_y_index, grid_map): - return n_x_index, n_y_index - else: # occupied - next_c_x_index, next_c_y_index = self.find_safe_turning_grid( - c_x_index, c_y_index, grid_map) - if (next_c_x_index is None) and (next_c_y_index is None): - # moving backward - next_c_x_index = -self.moving_direction + c_x_index - next_c_y_index = c_y_index - if self.check_occupied(next_c_x_index, next_c_y_index, grid_map, FloatGrid(1.0)): - # moved backward, but the grid is occupied by obstacle - return None, None - else: - # keep moving until end - while not self.check_occupied(next_c_x_index + self.moving_direction, next_c_y_index, grid_map): - next_c_x_index += self.moving_direction - self.swap_moving_direction() - return next_c_x_index, next_c_y_index - - @staticmethod - def check_occupied(c_x_index, c_y_index, grid_map, occupied_val=FloatGrid(0.5)): - return grid_map.check_occupied_from_xy_index(c_x_index, c_y_index, occupied_val) - - def find_safe_turning_grid(self, c_x_index, c_y_index, grid_map): - - for (d_x_ind, d_y_ind) in self.turing_window: - - next_x_ind = d_x_ind + c_x_index - next_y_ind = d_y_ind + c_y_index - - # found safe grid - if not self.check_occupied(next_x_ind, next_y_ind, grid_map): - return next_x_ind, next_y_ind - - return None, None - - def is_search_done(self, grid_map): - for ix in self.x_indexes_goal_y: - if not self.check_occupied(ix, self.goal_y, grid_map): - return False - - # all lower grid is occupied - return True - - def update_turning_window(self): - # turning window definition - # robot can move grid based on it. - self.turing_window = [ - (self.moving_direction, 0.0), - (self.moving_direction, self.sweep_direction), - (0, self.sweep_direction), - (-self.moving_direction, self.sweep_direction), - ] - - def swap_moving_direction(self): - self.moving_direction *= -1 - self.update_turning_window() - - def search_start_grid(self, grid_map): - x_inds = [] - y_ind = 0 - if self.sweep_direction == self.SweepDirection.DOWN: - x_inds, y_ind = search_free_grid_index_at_edge_y( - grid_map, from_upper=True) - elif self.sweep_direction == self.SweepDirection.UP: - x_inds, y_ind = search_free_grid_index_at_edge_y( - grid_map, from_upper=False) - - if self.moving_direction == self.MovingDirection.RIGHT: - return min(x_inds), y_ind - elif self.moving_direction == self.MovingDirection.LEFT: - return max(x_inds), y_ind - - raise ValueError("self.moving direction is invalid ") - - -def find_sweep_direction_and_start_position(ox, oy): - # find sweep_direction - max_dist = 0.0 - vec = [0.0, 0.0] - sweep_start_pos = [0.0, 0.0] - for i in range(len(ox) - 1): - dx = ox[i + 1] - ox[i] - dy = oy[i + 1] - oy[i] - d = np.hypot(dx, dy) - - if d > max_dist: - max_dist = d - vec = [dx, dy] - sweep_start_pos = [ox[i], oy[i]] - - return vec, sweep_start_pos - - -def convert_grid_coordinate(ox, oy, sweep_vec, sweep_start_position): - tx = [ix - sweep_start_position[0] for ix in ox] - ty = [iy - sweep_start_position[1] for iy in oy] - th = math.atan2(sweep_vec[1], sweep_vec[0]) - converted_xy = np.stack([tx, ty]).T @ rot_mat_2d(th) - - return converted_xy[:, 0], converted_xy[:, 1] - - -def convert_global_coordinate(x, y, sweep_vec, sweep_start_position): - th = math.atan2(sweep_vec[1], sweep_vec[0]) - converted_xy = np.stack([x, y]).T @ rot_mat_2d(-th) - rx = [ix + sweep_start_position[0] for ix in converted_xy[:, 0]] - ry = [iy + sweep_start_position[1] for iy in converted_xy[:, 1]] - return rx, ry - - -def search_free_grid_index_at_edge_y(grid_map, from_upper=False): - y_index = None - x_indexes = [] - - if from_upper: - x_range = range(grid_map.height)[::-1] - y_range = range(grid_map.width)[::-1] - else: - x_range = range(grid_map.height) - y_range = range(grid_map.width) - - for iy in x_range: - for ix in y_range: - if not SweepSearcher.check_occupied(ix, iy, grid_map): - y_index = iy - x_indexes.append(ix) - if y_index: - break - - return x_indexes, y_index - - -def setup_grid_map(ox, oy, resolution, sweep_direction, offset_grid=10): - width = math.ceil((max(ox) - min(ox)) / resolution) + offset_grid - height = math.ceil((max(oy) - min(oy)) / resolution) + offset_grid - center_x = (np.max(ox) + np.min(ox)) / 2.0 - center_y = (np.max(oy) + np.min(oy)) / 2.0 - - grid_map = GridMap(width, height, resolution, center_x, center_y) - grid_map.print_grid_map_info() - grid_map.set_value_from_polygon(ox, oy, FloatGrid(1.0), inside=False) - grid_map.expand_grid() - - x_inds_goal_y = [] - goal_y = 0 - if sweep_direction == SweepSearcher.SweepDirection.UP: - x_inds_goal_y, goal_y = search_free_grid_index_at_edge_y( - grid_map, from_upper=True) - elif sweep_direction == SweepSearcher.SweepDirection.DOWN: - x_inds_goal_y, goal_y = search_free_grid_index_at_edge_y( - grid_map, from_upper=False) - - return grid_map, x_inds_goal_y, goal_y - - -def sweep_path_search(sweep_searcher, grid_map, grid_search_animation=False): - # search start grid - c_x_index, c_y_index = sweep_searcher.search_start_grid(grid_map) - if not grid_map.set_value_from_xy_index(c_x_index, c_y_index, FloatGrid(0.5)): - print("Cannot find start grid") - return [], [] - - x, y = grid_map.calc_grid_central_xy_position_from_xy_index(c_x_index, - c_y_index) - px, py = [x], [y] - - fig, ax = None, None - if grid_search_animation: - fig, ax = plt.subplots() - # for stopping simulation with the esc key. - fig.canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - while True: - c_x_index, c_y_index = sweep_searcher.move_target_grid(c_x_index, - c_y_index, - grid_map) - - if sweep_searcher.is_search_done(grid_map) or ( - c_x_index is None or c_y_index is None): - print("Done") - break - - x, y = grid_map.calc_grid_central_xy_position_from_xy_index( - c_x_index, c_y_index) - - px.append(x) - py.append(y) - - grid_map.set_value_from_xy_index(c_x_index, c_y_index, FloatGrid(0.5)) - - if grid_search_animation: - grid_map.plot_grid_map(ax=ax) - plt.pause(1.0) - - return px, py - - -def planning(ox, oy, resolution, - moving_direction=SweepSearcher.MovingDirection.RIGHT, - sweeping_direction=SweepSearcher.SweepDirection.UP, - ): - sweep_vec, sweep_start_position = find_sweep_direction_and_start_position( - ox, oy) - - rox, roy = convert_grid_coordinate(ox, oy, sweep_vec, - sweep_start_position) - - grid_map, x_inds_goal_y, goal_y = setup_grid_map(rox, roy, resolution, - sweeping_direction) - - sweep_searcher = SweepSearcher(moving_direction, sweeping_direction, - x_inds_goal_y, goal_y) - - px, py = sweep_path_search(sweep_searcher, grid_map) - - rx, ry = convert_global_coordinate(px, py, sweep_vec, - sweep_start_position) - - print("Path length:", len(rx)) - - return rx, ry - - -def planning_animation(ox, oy, resolution): # pragma: no cover - px, py = planning(ox, oy, resolution) - - # animation - if do_animation: - for ipx, ipy in zip(px, py): - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(ox, oy, "-xb") - plt.plot(px, py, "-r") - plt.plot(ipx, ipy, "or") - plt.axis("equal") - plt.grid(True) - plt.pause(0.1) - - plt.cla() - plt.plot(ox, oy, "-xb") - plt.plot(px, py, "-r") - plt.axis("equal") - plt.grid(True) - plt.pause(0.1) - plt.close() - - -def main(): # pragma: no cover - print("start!!") - - ox = [0.0, 20.0, 50.0, 100.0, 130.0, 40.0, 0.0] - oy = [0.0, -20.0, 0.0, 30.0, 60.0, 80.0, 0.0] - resolution = 5.0 - planning_animation(ox, oy, resolution) - - ox = [0.0, 50.0, 50.0, 0.0, 0.0] - oy = [0.0, 0.0, 30.0, 30.0, 0.0] - resolution = 1.3 - planning_animation(ox, oy, resolution) - - ox = [0.0, 20.0, 50.0, 200.0, 130.0, 40.0, 0.0] - oy = [0.0, -80.0, 0.0, 30.0, 60.0, 80.0, 0.0] - resolution = 5.0 - planning_animation(ox, oy, resolution) - - if do_animation: - plt.show() - print("done!!") - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/HybridAStar/__init__.py b/PathPlanning/HybridAStar/__init__.py deleted file mode 100644 index 087dab646e1..00000000000 --- a/PathPlanning/HybridAStar/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -import os -import sys - -sys.path.append(os.path.dirname(os.path.abspath(__file__))) diff --git a/PathPlanning/HybridAStar/car.py b/PathPlanning/HybridAStar/car.py deleted file mode 100644 index 959db740784..00000000000 --- a/PathPlanning/HybridAStar/car.py +++ /dev/null @@ -1,113 +0,0 @@ -""" - -Car model for Hybrid A* path planning - -author: Zheng Zh (@Zhengzh) - -""" - -import sys -import pathlib -root_dir = pathlib.Path(__file__).parent.parent.parent -sys.path.append(str(root_dir)) - -from math import cos, sin, tan, pi - -import matplotlib.pyplot as plt -import numpy as np - -from utils.angle import rot_mat_2d - -WB = 3.0 # rear to front wheel -W = 2.0 # width of car -LF = 3.3 # distance from rear to vehicle front end -LB = 1.0 # distance from rear to vehicle back end -MAX_STEER = 0.6 # [rad] maximum steering angle - -BUBBLE_DIST = (LF - LB) / 2.0 # distance from rear to center of vehicle. -BUBBLE_R = np.hypot((LF + LB) / 2.0, W / 2.0) # bubble radius - -# vehicle rectangle vertices -VRX = [LF, LF, -LB, -LB, LF] -VRY = [W / 2, -W / 2, -W / 2, W / 2, W / 2] - - -def check_car_collision(x_list, y_list, yaw_list, ox, oy, kd_tree): - for i_x, i_y, i_yaw in zip(x_list, y_list, yaw_list): - cx = i_x + BUBBLE_DIST * cos(i_yaw) - cy = i_y + BUBBLE_DIST * sin(i_yaw) - - ids = kd_tree.query_ball_point([cx, cy], BUBBLE_R) - - if not ids: - continue - - if not rectangle_check(i_x, i_y, i_yaw, - [ox[i] for i in ids], [oy[i] for i in ids]): - return False # collision - - return True # no collision - - -def rectangle_check(x, y, yaw, ox, oy): - # transform obstacles to base link frame - rot = rot_mat_2d(yaw) - for iox, ioy in zip(ox, oy): - tx = iox - x - ty = ioy - y - converted_xy = np.stack([tx, ty]).T @ rot - rx, ry = converted_xy[0], converted_xy[1] - - if not (rx > LF or rx < -LB or ry > W / 2.0 or ry < -W / 2.0): - return False # collision - - return True # no collision - - -def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"): - """Plot arrow.""" - if not isinstance(x, float): - for (i_x, i_y, i_yaw) in zip(x, y, yaw): - plot_arrow(i_x, i_y, i_yaw) - else: - plt.arrow(x, y, length * cos(yaw), length * sin(yaw), - fc=fc, ec=ec, head_width=width, head_length=width, alpha=0.4) - - -def plot_car(x, y, yaw): - car_color = '-k' - c, s = cos(yaw), sin(yaw) - rot = rot_mat_2d(-yaw) - car_outline_x, car_outline_y = [], [] - for rx, ry in zip(VRX, VRY): - converted_xy = np.stack([rx, ry]).T @ rot - car_outline_x.append(converted_xy[0]+x) - car_outline_y.append(converted_xy[1]+y) - - arrow_x, arrow_y, arrow_yaw = c * 1.5 + x, s * 1.5 + y, yaw - plot_arrow(arrow_x, arrow_y, arrow_yaw) - - plt.plot(car_outline_x, car_outline_y, car_color) - - -def pi_2_pi(angle): - return (angle + pi) % (2 * pi) - pi - - -def move(x, y, yaw, distance, steer, L=WB): - x += distance * cos(yaw) - y += distance * sin(yaw) - yaw = pi_2_pi(yaw + distance * tan(steer) / L) # distance/2 - - return x, y, yaw - - -def main(): - x, y, yaw = 0., 0., 1. - plt.axis('equal') - plot_car(x, y, yaw) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/HybridAStar/dynamic_programming_heuristic.py b/PathPlanning/HybridAStar/dynamic_programming_heuristic.py deleted file mode 100644 index 09bcd556a69..00000000000 --- a/PathPlanning/HybridAStar/dynamic_programming_heuristic.py +++ /dev/null @@ -1,176 +0,0 @@ -""" - -A* grid based planning - -author: Nikos Kanargias (nkana@tee.gr) - -See Wikipedia article (https://en.wikipedia.org/wiki/A*_search_algorithm) - -""" - -import heapq -import math - -import matplotlib.pyplot as plt - -show_animation = False - - -class Node: - - def __init__(self, x, y, cost, parent_index): - self.x = x - self.y = y - self.cost = cost - self.parent_index = parent_index - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - -def calc_final_path(goal_node, closed_node_set, resolution): - # generate final course - rx, ry = [goal_node.x * resolution], [goal_node.y * resolution] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_node_set[parent_index] - rx.append(n.x * resolution) - ry.append(n.y * resolution) - parent_index = n.parent_index - - return rx, ry - - -def calc_distance_heuristic(gx, gy, ox, oy, resolution, 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] - resolution: grid resolution [m] - rr: robot radius[m] - """ - - goal_node = Node(round(gx / resolution), round(gy / resolution), 0.0, -1) - ox = [iox / resolution for iox in ox] - oy = [ioy / resolution for ioy in oy] - - obstacle_map, min_x, min_y, max_x, max_y, x_w, y_w = calc_obstacle_map( - ox, oy, resolution, rr) - - motion = get_motion_model() - - open_set, closed_set = dict(), dict() - open_set[calc_index(goal_node, x_w, min_x, min_y)] = goal_node - priority_queue = [(0, calc_index(goal_node, x_w, min_x, min_y))] - - while True: - if not priority_queue: - break - cost, c_id = heapq.heappop(priority_queue) - if c_id in open_set: - current = open_set[c_id] - closed_set[c_id] = current - open_set.pop(c_id) - else: - continue - - # show graph - if show_animation: # pragma: no cover - plt.plot(current.x * resolution, current.y * resolution, "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if len(closed_set.keys()) % 10 == 0: - plt.pause(0.001) - - # Remove the item from the open set - - # 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, x_w, min_x, min_y) - - if n_id in closed_set: - continue - - if not verify_node(node, obstacle_map, min_x, min_y, max_x, max_y): - continue - - if n_id not in open_set: - open_set[n_id] = node # Discover a new node - heapq.heappush( - priority_queue, - (node.cost, calc_index(node, x_w, min_x, min_y))) - else: - if open_set[n_id].cost >= node.cost: - # This path is the best until now. record it! - open_set[n_id] = node - heapq.heappush( - priority_queue, - (node.cost, calc_index(node, x_w, min_x, min_y))) - - return closed_set - - -def verify_node(node, obstacle_map, min_x, min_y, max_x, max_y): - if node.x < min_x: - return False - elif node.y < min_y: - return False - elif node.x >= max_x: - return False - elif node.y >= max_y: - return False - - if obstacle_map[node.x][node.y]: - return False - - return True - - -def calc_obstacle_map(ox, oy, resolution, vr): - min_x = round(min(ox)) - min_y = round(min(oy)) - max_x = round(max(ox)) - max_y = round(max(oy)) - - x_width = round(max_x - min_x) - y_width = round(max_y - min_y) - - # obstacle map generation - obstacle_map = [[False for _ in range(y_width)] for _ in range(x_width)] - for ix in range(x_width): - x = ix + min_x - for iy in range(y_width): - y = iy + min_y - # print(x, y) - for iox, ioy in zip(ox, oy): - d = math.hypot(iox - x, ioy - y) - if d <= vr / resolution: - obstacle_map[ix][iy] = True - break - - return obstacle_map, min_x, min_y, max_x, max_y, x_width, y_width - - -def calc_index(node, x_width, x_min, y_min): - return (node.y - y_min) * x_width + (node.x - x_min) - - -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 diff --git a/PathPlanning/HybridAStar/hybrid_a_star.py b/PathPlanning/HybridAStar/hybrid_a_star.py deleted file mode 100644 index 0fa04189c6c..00000000000 --- a/PathPlanning/HybridAStar/hybrid_a_star.py +++ /dev/null @@ -1,441 +0,0 @@ -""" - -Hybrid A* path planning - -author: Zheng Zh (@Zhengzh) - -""" - -import heapq -import math -import matplotlib.pyplot as plt -import numpy as np -from scipy.spatial import cKDTree -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from dynamic_programming_heuristic import calc_distance_heuristic -from ReedsSheppPath import reeds_shepp_path_planning as rs -from car import move, check_car_collision, MAX_STEER, WB, plot_car, BUBBLE_R - -XY_GRID_RESOLUTION = 2.0 # [m] -YAW_GRID_RESOLUTION = np.deg2rad(15.0) # [rad] -MOTION_RESOLUTION = 0.1 # [m] path interpolate resolution -N_STEER = 20 # number of steer command - -SB_COST = 100.0 # switch back penalty cost -BACK_COST = 5.0 # backward penalty cost -STEER_CHANGE_COST = 5.0 # steer angle change penalty cost -STEER_COST = 1.0 # steer angle change penalty cost -H_COST = 5.0 # Heuristic cost - -show_animation = True - - -class Node: - - def __init__(self, x_ind, y_ind, yaw_ind, direction, - x_list, y_list, yaw_list, directions, - steer=0.0, parent_index=None, cost=None): - self.x_index = x_ind - self.y_index = y_ind - self.yaw_index = yaw_ind - self.direction = direction - self.x_list = x_list - self.y_list = y_list - self.yaw_list = yaw_list - self.directions = directions - self.steer = steer - self.parent_index = parent_index - self.cost = cost - - -class Path: - - def __init__(self, x_list, y_list, yaw_list, direction_list, cost): - self.x_list = x_list - self.y_list = y_list - self.yaw_list = yaw_list - self.direction_list = direction_list - self.cost = cost - - -class Config: - - def __init__(self, ox, oy, xy_resolution, yaw_resolution): - min_x_m = min(ox) - min_y_m = min(oy) - max_x_m = max(ox) - max_y_m = max(oy) - - ox.append(min_x_m) - oy.append(min_y_m) - ox.append(max_x_m) - oy.append(max_y_m) - - self.min_x = round(min_x_m / xy_resolution) - self.min_y = round(min_y_m / xy_resolution) - self.max_x = round(max_x_m / xy_resolution) - self.max_y = round(max_y_m / xy_resolution) - - self.x_w = round(self.max_x - self.min_x) - self.y_w = round(self.max_y - self.min_y) - - self.min_yaw = round(- math.pi / yaw_resolution) - 1 - self.max_yaw = round(math.pi / yaw_resolution) - self.yaw_w = round(self.max_yaw - self.min_yaw) - - -def calc_motion_inputs(): - for steer in np.concatenate((np.linspace(-MAX_STEER, MAX_STEER, - N_STEER), [0.0])): - for d in [1, -1]: - yield [steer, d] - - -def get_neighbors(current, config, ox, oy, kd_tree): - for steer, d in calc_motion_inputs(): - node = calc_next_node(current, steer, d, config, ox, oy, kd_tree) - if node and verify_index(node, config): - yield node - - -def calc_next_node(current, steer, direction, config, ox, oy, kd_tree): - x, y, yaw = current.x_list[-1], current.y_list[-1], current.yaw_list[-1] - - arc_l = XY_GRID_RESOLUTION * 1.5 - x_list, y_list, yaw_list, direction_list = [], [], [], [] - for _ in np.arange(0, arc_l, MOTION_RESOLUTION): - x, y, yaw = move(x, y, yaw, MOTION_RESOLUTION * direction, steer) - x_list.append(x) - y_list.append(y) - yaw_list.append(yaw) - direction_list.append(direction == 1) - - if not check_car_collision(x_list, y_list, yaw_list, ox, oy, kd_tree): - return None - - d = direction == 1 - x_ind = round(x / XY_GRID_RESOLUTION) - y_ind = round(y / XY_GRID_RESOLUTION) - yaw_ind = round(yaw / YAW_GRID_RESOLUTION) - - added_cost = 0.0 - - if d != current.direction: - added_cost += SB_COST - - # steer penalty - added_cost += STEER_COST * abs(steer) - - # steer change penalty - added_cost += STEER_CHANGE_COST * abs(current.steer - steer) - - cost = current.cost + added_cost + arc_l - - node = Node(x_ind, y_ind, yaw_ind, d, x_list, - y_list, yaw_list, direction_list, - parent_index=calc_index(current, config), - cost=cost, steer=steer) - - return node - - -def is_same_grid(n1, n2): - if n1.x_index == n2.x_index \ - and n1.y_index == n2.y_index \ - and n1.yaw_index == n2.yaw_index: - return True - return False - - -def analytic_expansion(current, goal, ox, oy, kd_tree): - start_x = current.x_list[-1] - start_y = current.y_list[-1] - start_yaw = current.yaw_list[-1] - - goal_x = goal.x_list[-1] - goal_y = goal.y_list[-1] - goal_yaw = goal.yaw_list[-1] - - max_curvature = math.tan(MAX_STEER) / WB - paths = rs.calc_paths(start_x, start_y, start_yaw, - goal_x, goal_y, goal_yaw, - max_curvature, step_size=MOTION_RESOLUTION) - - if not paths: - return None - - best_path, best = None, None - - for path in paths: - if check_car_collision(path.x, path.y, path.yaw, ox, oy, kd_tree): - cost = calc_rs_path_cost(path) - if not best or best > cost: - best = cost - best_path = path - - return best_path - - -def update_node_with_analytic_expansion(current, goal, - c, ox, oy, kd_tree): - path = analytic_expansion(current, goal, ox, oy, kd_tree) - - if path: - if show_animation: - plt.plot(path.x, path.y) - f_x = path.x[1:] - f_y = path.y[1:] - f_yaw = path.yaw[1:] - - f_cost = current.cost + calc_rs_path_cost(path) - f_parent_index = calc_index(current, c) - - fd = [] - for d in path.directions[1:]: - fd.append(d >= 0) - - f_steer = 0.0 - f_path = Node(current.x_index, current.y_index, current.yaw_index, - current.direction, f_x, f_y, f_yaw, fd, - cost=f_cost, parent_index=f_parent_index, steer=f_steer) - return True, f_path - - return False, None - - -def calc_rs_path_cost(reed_shepp_path): - cost = 0.0 - for length in reed_shepp_path.lengths: - if length >= 0: # forward - cost += length - else: # back - cost += abs(length) * BACK_COST - - # switch back penalty - for i in range(len(reed_shepp_path.lengths) - 1): - # switch back - if reed_shepp_path.lengths[i] * reed_shepp_path.lengths[i + 1] < 0.0: - cost += SB_COST - - # steer penalty - for course_type in reed_shepp_path.ctypes: - if course_type != "S": # curve - cost += STEER_COST * abs(MAX_STEER) - - # ==steer change penalty - # calc steer profile - n_ctypes = len(reed_shepp_path.ctypes) - u_list = [0.0] * n_ctypes - for i in range(n_ctypes): - if reed_shepp_path.ctypes[i] == "R": - u_list[i] = - MAX_STEER - elif reed_shepp_path.ctypes[i] == "L": - u_list[i] = MAX_STEER - - for i in range(len(reed_shepp_path.ctypes) - 1): - cost += STEER_CHANGE_COST * abs(u_list[i + 1] - u_list[i]) - - return cost - - -def hybrid_a_star_planning(start, goal, ox, oy, xy_resolution, yaw_resolution): - """ - start: start node - goal: goal node - ox: x position list of Obstacles [m] - oy: y position list of Obstacles [m] - xy_resolution: grid resolution [m] - yaw_resolution: yaw angle resolution [rad] - """ - - start[2], goal[2] = rs.pi_2_pi(start[2]), rs.pi_2_pi(goal[2]) - tox, toy = ox[:], oy[:] - - obstacle_kd_tree = cKDTree(np.vstack((tox, toy)).T) - - config = Config(tox, toy, xy_resolution, yaw_resolution) - - start_node = Node(round(start[0] / xy_resolution), - round(start[1] / xy_resolution), - round(start[2] / yaw_resolution), True, - [start[0]], [start[1]], [start[2]], [True], cost=0) - goal_node = Node(round(goal[0] / xy_resolution), - round(goal[1] / xy_resolution), - round(goal[2] / yaw_resolution), True, - [goal[0]], [goal[1]], [goal[2]], [True]) - - openList, closedList = {}, {} - - h_dp = calc_distance_heuristic( - goal_node.x_list[-1], goal_node.y_list[-1], - ox, oy, xy_resolution, BUBBLE_R) - - pq = [] - openList[calc_index(start_node, config)] = start_node - heapq.heappush(pq, (calc_cost(start_node, h_dp, config), - calc_index(start_node, config))) - final_path = None - - while True: - if not openList: - print("Error: Cannot find path, No open set") - return Path([], [], [], [], 0) - - cost, c_id = heapq.heappop(pq) - if c_id in openList: - current = openList.pop(c_id) - closedList[c_id] = current - else: - continue - - if show_animation: # pragma: no cover - plt.plot(current.x_list[-1], current.y_list[-1], "xc") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if len(closedList.keys()) % 10 == 0: - plt.pause(0.001) - - is_updated, final_path = update_node_with_analytic_expansion( - current, goal_node, config, ox, oy, obstacle_kd_tree) - - if is_updated: - print("path found") - break - - for neighbor in get_neighbors(current, config, ox, oy, - obstacle_kd_tree): - neighbor_index = calc_index(neighbor, config) - if neighbor_index in closedList: - continue - if neighbor_index not in openList \ - or openList[neighbor_index].cost > neighbor.cost: - heapq.heappush( - pq, (calc_cost(neighbor, h_dp, config), - neighbor_index)) - openList[neighbor_index] = neighbor - - path = get_final_path(closedList, final_path) - return path - - -def calc_cost(n, h_dp, c): - ind = (n.y_index - c.min_y) * c.x_w + (n.x_index - c.min_x) - if ind not in h_dp: - return n.cost + 999999999 # collision cost - return n.cost + H_COST * h_dp[ind].cost - - -def get_final_path(closed, goal_node): - reversed_x, reversed_y, reversed_yaw = \ - list(reversed(goal_node.x_list)), list(reversed(goal_node.y_list)), \ - list(reversed(goal_node.yaw_list)) - direction = list(reversed(goal_node.directions)) - nid = goal_node.parent_index - final_cost = goal_node.cost - - while nid: - n = closed[nid] - reversed_x.extend(list(reversed(n.x_list))) - reversed_y.extend(list(reversed(n.y_list))) - reversed_yaw.extend(list(reversed(n.yaw_list))) - direction.extend(list(reversed(n.directions))) - - nid = n.parent_index - - reversed_x = list(reversed(reversed_x)) - reversed_y = list(reversed(reversed_y)) - reversed_yaw = list(reversed(reversed_yaw)) - direction = list(reversed(direction)) - - # adjust first direction - direction[0] = direction[1] - - path = Path(reversed_x, reversed_y, reversed_yaw, direction, final_cost) - - return path - - -def verify_index(node, c): - x_ind, y_ind = node.x_index, node.y_index - if c.min_x <= x_ind <= c.max_x and c.min_y <= y_ind <= c.max_y: - return True - - return False - - -def calc_index(node, c): - ind = (node.yaw_index - c.min_yaw) * c.x_w * c.y_w + \ - (node.y_index - c.min_y) * c.x_w + (node.x_index - c.min_x) - - if ind <= 0: - print("Error(calc_index):", ind) - - return ind - - -def main(): - print("Start Hybrid A* planning") - - 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) - - # Set Initial parameters - start = [10.0, 10.0, np.deg2rad(90.0)] - goal = [50.0, 50.0, np.deg2rad(-90.0)] - - print("start : ", start) - print("goal : ", goal) - - if show_animation: - plt.plot(ox, oy, ".k") - rs.plot_arrow(start[0], start[1], start[2], fc='g') - rs.plot_arrow(goal[0], goal[1], goal[2]) - - plt.grid(True) - plt.axis("equal") - - path = hybrid_a_star_planning( - start, goal, ox, oy, XY_GRID_RESOLUTION, YAW_GRID_RESOLUTION) - - x = path.x_list - y = path.y_list - yaw = path.yaw_list - - if show_animation: - for i_x, i_y, i_yaw in zip(x, y, yaw): - plt.cla() - plt.plot(ox, oy, ".k") - plt.plot(x, y, "-r", label="Hybrid A* path") - plt.grid(True) - plt.axis("equal") - plot_car(i_x, i_y, i_yaw) - plt.pause(0.0001) - - print(__file__ + " done!!") - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/InformedRRTStar/informed_rrt_star.py b/PathPlanning/InformedRRTStar/informed_rrt_star.py deleted file mode 100644 index 0483949c996..00000000000 --- a/PathPlanning/InformedRRTStar/informed_rrt_star.py +++ /dev/null @@ -1,350 +0,0 @@ -""" -Informed RRT* path planning - -author: Karan Chawla - Atsushi Sakai(@Atsushi_twi) - -Reference: Informed RRT*: Optimal Sampling-based Path planning Focused via -Direct Sampling of an Admissible Ellipsoidal Heuristic -https://arxiv.org/pdf/1404.2334 - -""" -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import copy -import math -import random - -import matplotlib.pyplot as plt -import numpy as np - -from utils.angle import rot_mat_2d - -show_animation = True - - -class InformedRRTStar: - - def __init__(self, start, goal, obstacle_list, rand_area, expand_dis=0.5, - goal_sample_rate=10, max_iter=200): - - self.start = Node(start[0], start[1]) - self.goal = Node(goal[0], goal[1]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.expand_dis = expand_dis - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.obstacle_list = obstacle_list - self.node_list = None - - def informed_rrt_star_search(self, animation=True): - - self.node_list = [self.start] - # max length we expect to find in our 'informed' sample space, - # starts as infinite - c_best = float('inf') - solution_set = set() - path = None - - # Computing the sampling space - c_min = math.hypot(self.start.x - self.goal.x, - self.start.y - self.goal.y) - x_center = np.array([[(self.start.x + self.goal.x) / 2.0], - [(self.start.y + self.goal.y) / 2.0], [0]]) - a1 = np.array([[(self.goal.x - self.start.x) / c_min], - [(self.goal.y - self.start.y) / c_min], [0]]) - - e_theta = math.atan2(a1[1, 0], a1[0, 0]) - # first column of identity matrix transposed - id1_t = np.array([1.0, 0.0, 0.0]).reshape(1, 3) - m = a1 @ id1_t - u, s, vh = np.linalg.svd(m, True, True) - c = u @ np.diag( - [1.0, 1.0, - np.linalg.det(u) * np.linalg.det(np.transpose(vh))]) @ vh - - for i in range(self.max_iter): - # Sample space is defined by c_best - # c_min is the minimum distance between the start point and - # the goal x_center is the midpoint between the start and the - # goal c_best changes when a new path is found - - rnd = self.informed_sample(c_best, c_min, x_center, c) - n_ind = self.get_nearest_list_index(self.node_list, rnd) - nearest_node = self.node_list[n_ind] - # steer - theta = math.atan2(rnd[1] - nearest_node.y, - rnd[0] - nearest_node.x) - new_node = self.get_new_node(theta, n_ind, nearest_node) - d = self.line_cost(nearest_node, new_node) - - no_collision = self.check_collision(nearest_node, theta, d) - - if no_collision: - near_inds = self.find_near_nodes(new_node) - new_node = self.choose_parent(new_node, near_inds) - - self.node_list.append(new_node) - self.rewire(new_node, near_inds) - - if self.is_near_goal(new_node): - if self.check_segment_collision(new_node.x, new_node.y, - self.goal.x, self.goal.y): - solution_set.add(new_node) - last_index = len(self.node_list) - 1 - temp_path = self.get_final_course(last_index) - temp_path_len = self.get_path_len(temp_path) - if temp_path_len < c_best: - path = temp_path - c_best = temp_path_len - if animation: - self.draw_graph(x_center=x_center, c_best=c_best, c_min=c_min, - e_theta=e_theta, rnd=rnd) - - return path - - def choose_parent(self, new_node, near_inds): - if len(near_inds) == 0: - return new_node - - d_list = [] - for i in near_inds: - dx = new_node.x - self.node_list[i].x - dy = new_node.y - self.node_list[i].y - d = math.hypot(dx, dy) - theta = math.atan2(dy, dx) - if self.check_collision(self.node_list[i], theta, d): - d_list.append(self.node_list[i].cost + d) - else: - d_list.append(float('inf')) - - min_cost = min(d_list) - min_ind = near_inds[d_list.index(min_cost)] - - if min_cost == float('inf'): - print("min cost is inf") - return new_node - - new_node.cost = min_cost - new_node.parent = min_ind - - return new_node - - def find_near_nodes(self, new_node): - n_node = len(self.node_list) - r = 50.0 * math.sqrt(math.log(n_node) / n_node) - d_list = [(node.x - new_node.x) ** 2 + (node.y - new_node.y) ** 2 for - node in self.node_list] - near_inds = [d_list.index(i) for i in d_list if i <= r ** 2] - return near_inds - - def informed_sample(self, c_max, c_min, x_center, c): - if c_max < float('inf'): - r = [c_max / 2.0, math.sqrt(c_max ** 2 - c_min ** 2) / 2.0, - math.sqrt(c_max ** 2 - c_min ** 2) / 2.0] - rl = np.diag(r) - x_ball = self.sample_unit_ball() - rnd = np.dot(np.dot(c, rl), x_ball) + x_center - rnd = [rnd[(0, 0)], rnd[(1, 0)]] - else: - rnd = self.sample_free_space() - - return rnd - - @staticmethod - def sample_unit_ball(): - a = random.random() - b = random.random() - - if b < a: - a, b = b, a - - sample = (b * math.cos(2 * math.pi * a / b), - b * math.sin(2 * math.pi * a / b)) - return np.array([[sample[0]], [sample[1]], [0]]) - - def sample_free_space(self): - if random.randint(0, 100) > self.goal_sample_rate: - rnd = [random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand)] - else: - rnd = [self.goal.x, self.goal.y] - - return rnd - - @staticmethod - def get_path_len(path): - path_len = 0 - for i in range(1, len(path)): - node1_x = path[i][0] - node1_y = path[i][1] - node2_x = path[i - 1][0] - node2_y = path[i - 1][1] - path_len += math.hypot(node1_x - node2_x, node1_y - node2_y) - - return path_len - - @staticmethod - def line_cost(node1, node2): - return math.hypot(node1.x - node2.x, node1.y - node2.y) - - @staticmethod - def get_nearest_list_index(nodes, rnd): - d_list = [(node.x - rnd[0]) ** 2 + (node.y - rnd[1]) ** 2 for node in - nodes] - min_index = d_list.index(min(d_list)) - return min_index - - def get_new_node(self, theta, n_ind, nearest_node): - new_node = copy.deepcopy(nearest_node) - - new_node.x += self.expand_dis * math.cos(theta) - new_node.y += self.expand_dis * math.sin(theta) - - new_node.cost += self.expand_dis - new_node.parent = n_ind - return new_node - - def is_near_goal(self, node): - d = self.line_cost(node, self.goal) - if d < self.expand_dis: - return True - return False - - def rewire(self, new_node, near_inds): - n_node = len(self.node_list) - for i in near_inds: - near_node = self.node_list[i] - - d = math.hypot(near_node.x - new_node.x, near_node.y - new_node.y) - - s_cost = new_node.cost + d - - if near_node.cost > s_cost: - theta = math.atan2(new_node.y - near_node.y, - new_node.x - near_node.x) - if self.check_collision(near_node, theta, d): - near_node.parent = n_node - 1 - near_node.cost = s_cost - - @staticmethod - def distance_squared_point_to_segment(v, w, p): - # Return minimum distance between line segment vw and point p - if np.array_equal(v, w): - return (p - v).dot(p - v) # v == w case - l2 = (w - v).dot(w - v) # i.e. |w-v|^2 - avoid a sqrt - # Consider the line extending the segment, - # parameterized as v + t (w - v). - # We find projection of point p onto the line. - # It falls where t = [(p-v) . (w-v)] / |w-v|^2 - # We clamp t from [0,1] to handle points outside the segment vw. - t = max(0, min(1, (p - v).dot(w - v) / l2)) - projection = v + t * (w - v) # Projection falls on the segment - return (p - projection).dot(p - projection) - - def check_segment_collision(self, x1, y1, x2, y2): - for (ox, oy, size) in self.obstacle_list: - dd = self.distance_squared_point_to_segment( - np.array([x1, y1]), np.array([x2, y2]), np.array([ox, oy])) - if dd <= size ** 2: - return False # collision - return True - - def check_collision(self, near_node, theta, d): - tmp_node = copy.deepcopy(near_node) - end_x = tmp_node.x + math.cos(theta) * d - end_y = tmp_node.y + math.sin(theta) * d - return self.check_segment_collision(tmp_node.x, tmp_node.y, - end_x, end_y) - - def get_final_course(self, last_index): - path = [[self.goal.x, self.goal.y]] - while self.node_list[last_index].parent is not None: - node = self.node_list[last_index] - path.append([node.x, node.y]) - last_index = node.parent - path.append([self.start.x, self.start.y]) - return path - - def draw_graph(self, x_center=None, c_best=None, c_min=None, e_theta=None, - rnd=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', lambda event: - [exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd[0], rnd[1], "^k") - if c_best != float('inf'): - self.plot_ellipse(x_center, c_best, c_min, e_theta) - - for node in self.node_list: - if node.parent is not None: - if node.x or node.y is not None: - plt.plot([node.x, self.node_list[node.parent].x], - [node.y, self.node_list[node.parent].y], "-g") - - for (ox, oy, size) in self.obstacle_list: - plt.plot(ox, oy, "ok", ms=30 * size) - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.goal.x, self.goal.y, "xr") - plt.axis([self.min_rand, self.max_rand, self.min_rand, self.max_rand]) - plt.grid(True) - plt.pause(0.01) - - @staticmethod - def plot_ellipse(x_center, c_best, c_min, e_theta): # pragma: no cover - - a = math.sqrt(c_best ** 2 - c_min ** 2) / 2.0 - b = c_best / 2.0 - angle = math.pi / 2.0 - e_theta - cx = x_center[0] - cy = x_center[1] - t = np.arange(0, 2 * math.pi + 0.1, 0.1) - x = [a * math.cos(it) for it in t] - y = [b * math.sin(it) for it in t] - fx = rot_mat_2d(-angle) @ np.array([x, y]) - px = np.array(fx[0, :] + cx).flatten() - py = np.array(fx[1, :] + cy).flatten() - plt.plot(cx, cy, "xc") - plt.plot(px, py, "--c") - - -class Node: - - def __init__(self, x, y): - self.x = x - self.y = y - self.cost = 0.0 - self.parent = None - - -def main(): - print("Start informed rrt star planning") - - # create obstacles - obstacle_list = [(5, 5, 0.5), (9, 6, 1), (7, 5, 1), (1, 5, 1), (3, 6, 1), - (7, 9, 1)] - - # Set params - rrt = InformedRRTStar(start=[0, 0], goal=[5, 10], rand_area=[-2, 15], - obstacle_list=obstacle_list) - path = rrt.informed_rrt_star_search(animation=show_animation) - print("Done!!") - - # Plot path - if show_animation: - rrt.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.01) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/LQRPlanner/lqr_planner.py b/PathPlanning/LQRPlanner/lqr_planner.py deleted file mode 100644 index 0f58f93ea39..00000000000 --- a/PathPlanning/LQRPlanner/lqr_planner.py +++ /dev/null @@ -1,146 +0,0 @@ -""" - -LQR local path planning - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math -import random - -import matplotlib.pyplot as plt -import numpy as np -import scipy.linalg as la - -SHOW_ANIMATION = True - - -class LQRPlanner: - - def __init__(self): - self.MAX_TIME = 100.0 # Maximum simulation time - self.DT = 0.1 # Time tick - self.GOAL_DIST = 0.1 - self.MAX_ITER = 150 - self.EPS = 0.01 - - def lqr_planning(self, sx, sy, gx, gy, show_animation=True): - - rx, ry = [sx], [sy] - - x = np.array([sx - gx, sy - gy]).reshape(2, 1) # State vector - - # Linear system model - A, B = self.get_system_model() - - found_path = False - - time = 0.0 - while time <= self.MAX_TIME: - time += self.DT - - u = self.lqr_control(A, B, x) - - x = A @ x + B @ u - - rx.append(x[0, 0] + gx) - ry.append(x[1, 0] + gy) - - d = math.hypot(gx - rx[-1], gy - ry[-1]) - if d <= self.GOAL_DIST: - found_path = True - break - - # animation - if show_animation: # pragma: no cover - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(sx, sy, "or") - plt.plot(gx, gy, "ob") - plt.plot(rx, ry, "-r") - plt.axis("equal") - plt.pause(1.0) - - if not found_path: - print("Cannot found path") - return [], [] - - return rx, ry - - def solve_dare(self, A, B, Q, R): - """ - solve a discrete time_Algebraic Riccati equation (DARE) - """ - X, Xn = Q, Q - - for i in range(self.MAX_ITER): - Xn = A.T * X * A - A.T * X * B * \ - la.inv(R + B.T * X * B) * B.T * X * A + Q - if (abs(Xn - X)).max() < self.EPS: - break - X = Xn - - return Xn - - def dlqr(self, A, B, Q, R): - """Solve the discrete time lqr controller. - x[k+1] = A x[k] + B u[k] - cost = sum x[k].T*Q*x[k] + u[k].T*R*u[k] - # ref Bertsekas, p.151 - """ - - # first, try to solve the ricatti equation - X = self.solve_dare(A, B, Q, R) - - # compute the LQR gain - K = la.inv(B.T @ X @ B + R) @ (B.T @ X @ A) - - eigValues = la.eigvals(A - B @ K) - - return K, X, eigValues - - def get_system_model(self): - - A = np.array([[self.DT, 1.0], - [0.0, self.DT]]) - B = np.array([0.0, 1.0]).reshape(2, 1) - - return A, B - - def lqr_control(self, A, B, x): - - Kopt, X, ev = self.dlqr(A, B, np.eye(2), np.eye(1)) - - u = -Kopt @ x - - return u - - -def main(): - print(__file__ + " start!!") - - ntest = 10 # number of goal - area = 100.0 # sampling area - - lqr_planner = LQRPlanner() - - for i in range(ntest): - sx = 6.0 - sy = 6.0 - gx = random.uniform(-area, area) - gy = random.uniform(-area, area) - - rx, ry = lqr_planner.lqr_planning(sx, sy, gx, gy, show_animation=SHOW_ANIMATION) - - if SHOW_ANIMATION: # pragma: no cover - plt.plot(sx, sy, "or") - plt.plot(gx, gy, "ob") - plt.plot(rx, ry, "-r") - plt.axis("equal") - plt.pause(1.0) - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/LQRRRTStar/lqr_rrt_star.py b/PathPlanning/LQRRRTStar/lqr_rrt_star.py deleted file mode 100644 index 0ed08123eab..00000000000 --- a/PathPlanning/LQRRRTStar/lqr_rrt_star.py +++ /dev/null @@ -1,241 +0,0 @@ -""" - -Path planning code with LQR RRT* - -author: AtsushiSakai(@Atsushi_twi) - -""" -import copy -import math -import random -import matplotlib.pyplot as plt -import numpy as np -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from LQRPlanner.lqr_planner import LQRPlanner -from RRTStar.rrt_star import RRTStar - -show_animation = True - - -class LQRRRTStar(RRTStar): - """ - Class for RRT star planning with LQR planning - """ - - def __init__(self, start, goal, obstacle_list, rand_area, - goal_sample_rate=10, - max_iter=200, - connect_circle_dist=50.0, - step_size=0.2, - robot_radius=0.0, - ): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacleList:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - robot_radius: robot body modeled as circle with given radius - - """ - self.start = self.Node(start[0], start[1]) - self.end = self.Node(goal[0], goal[1]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.obstacle_list = obstacle_list - self.connect_circle_dist = connect_circle_dist - - self.curvature = 1.0 - self.goal_xy_th = 0.5 - self.step_size = step_size - self.robot_radius = robot_radius - - self.lqr_planner = LQRPlanner() - - def planning(self, animation=True, search_until_max_iter=True): - """ - RRT Star planning - - animation: flag for animation on or off - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - print("Iter:", i, ", number of nodes:", len(self.node_list)) - rnd = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd) - new_node = self.steer(self.node_list[nearest_ind], rnd) - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - near_indexes = self.find_near_nodes(new_node) - new_node = self.choose_parent(new_node, near_indexes) - if new_node: - self.node_list.append(new_node) - self.rewire(new_node, near_indexes) - - if animation and i % 5 == 0: - self.draw_graph(rnd) - - if (not search_until_max_iter) and new_node: # check reaching the goal - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - - print("reached max iteration") - - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - else: - print("Cannot find path") - - return None - - def draw_graph(self, rnd=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd.x, rnd.y, "^k") - for node in self.node_list: - if node.parent: - plt.plot(node.path_x, node.path_y, "-g") - - for (ox, oy, size) in self.obstacle_list: - plt.plot(ox, oy, "ok", ms=30 * size) - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.end.x, self.end.y, "xr") - plt.axis([-2, 15, -2, 15]) - plt.grid(True) - plt.pause(0.01) - - def search_best_goal_node(self): - dist_to_goal_list = [self.calc_dist_to_goal(n.x, n.y) for n in self.node_list] - goal_inds = [dist_to_goal_list.index(i) for i in dist_to_goal_list if i <= self.goal_xy_th] - - if not goal_inds: - return None - - min_cost = min([self.node_list[i].cost for i in goal_inds]) - for i in goal_inds: - if self.node_list[i].cost == min_cost: - return i - - return None - - def calc_new_cost(self, from_node, to_node): - - wx, wy = self.lqr_planner.lqr_planning( - from_node.x, from_node.y, to_node.x, to_node.y, show_animation=False) - - px, py, course_lengths = self.sample_path(wx, wy, self.step_size) - - if not course_lengths: - return float("inf") - - return from_node.cost + sum(course_lengths) - - def get_random_node(self): - - if random.randint(0, 100) > self.goal_sample_rate: - rnd = self.Node(random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand) - ) - else: # goal point sampling - rnd = self.Node(self.end.x, self.end.y) - - return rnd - - def generate_final_course(self, goal_index): - print("final") - path = [[self.end.x, self.end.y]] - node = self.node_list[goal_index] - while node.parent: - for (ix, iy) in zip(reversed(node.path_x), reversed(node.path_y)): - path.append([ix, iy]) - node = node.parent - path.append([self.start.x, self.start.y]) - return path - - def sample_path(self, wx, wy, step): - - px, py, clen = [], [], [] - - for i in range(len(wx) - 1): - - for t in np.arange(0.0, 1.0, step): - px.append(t * wx[i + 1] + (1.0 - t) * wx[i]) - py.append(t * wy[i + 1] + (1.0 - t) * wy[i]) - - dx = np.diff(px) - dy = np.diff(py) - - clen = [math.hypot(idx, idy) for (idx, idy) in zip(dx, dy)] - - return px, py, clen - - def steer(self, from_node, to_node): - - wx, wy = self.lqr_planner.lqr_planning( - from_node.x, from_node.y, to_node.x, to_node.y, show_animation=False) - - px, py, course_lens = self.sample_path(wx, wy, self.step_size) - - if px is None: - return None - - newNode = copy.deepcopy(from_node) - newNode.x = px[-1] - newNode.y = py[-1] - newNode.path_x = px - newNode.path_y = py - newNode.cost += sum([abs(c) for c in course_lens]) - newNode.parent = from_node - - return newNode - - -def main(maxIter=200): - print("Start " + __file__) - - # ====Search Path with RRT==== - obstacleList = [ - (5, 5, 1), - (4, 6, 1), - (4, 7.5, 1), - (4, 9, 1), - (6, 5, 1), - (7, 5, 1) - ] # [x,y,size] - - # Set Initial parameters - start = [0.0, 0.0] - goal = [6.0, 7.0] - - lqr_rrt_star = LQRRRTStar(start, goal, - obstacleList, - [-2.0, 15.0]) - path = lqr_rrt_star.planning(animation=show_animation) - - # Draw final path - if show_animation: # pragma: no cover - lqr_rrt_star.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.001) - plt.show() - - print("Done") - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/ModelPredictiveTrajectoryGenerator/__init__.py b/PathPlanning/ModelPredictiveTrajectoryGenerator/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/ModelPredictiveTrajectoryGenerator/lookup_table_generator.py b/PathPlanning/ModelPredictiveTrajectoryGenerator/lookup_table_generator.py deleted file mode 100644 index 4c3b32f2807..00000000000 --- a/PathPlanning/ModelPredictiveTrajectoryGenerator/lookup_table_generator.py +++ /dev/null @@ -1,110 +0,0 @@ -""" - -Lookup Table generation for model predictive trajectory generator - -author: Atsushi Sakai - -""" -import sys -import pathlib -path_planning_dir = pathlib.Path(__file__).parent.parent -sys.path.append(str(path_planning_dir)) - -from matplotlib import pyplot as plt -import numpy as np -import math - -from ModelPredictiveTrajectoryGenerator import trajectory_generator,\ - motion_model - - -def calc_states_list(max_yaw=np.deg2rad(-30.0)): - - x = np.arange(10.0, 30.0, 5.0) - y = np.arange(0.0, 20.0, 2.0) - yaw = np.arange(-max_yaw, max_yaw, max_yaw) - - states = [] - for iyaw in yaw: - for iy in y: - for ix in x: - states.append([ix, iy, iyaw]) - print("n_state:", len(states)) - - return states - - -def search_nearest_one_from_lookup_table(tx, ty, tyaw, lookup_table): - mind = float("inf") - minid = -1 - - for (i, table) in enumerate(lookup_table): - - dx = tx - table[0] - dy = ty - table[1] - dyaw = tyaw - table[2] - d = math.sqrt(dx ** 2 + dy ** 2 + dyaw ** 2) - if d <= mind: - minid = i - mind = d - - # print(minid) - - return lookup_table[minid] - - -def save_lookup_table(file_name, table): - np.savetxt(file_name, np.array(table), - fmt='%s', delimiter=",", header="x,y,yaw,s,km,kf", comments="") - - print("lookup table file is saved as " + file_name) - - -def generate_lookup_table(): - states = calc_states_list(max_yaw=np.deg2rad(-30.0)) - k0 = 0.0 - - # x, y, yaw, s, km, kf - lookup_table = [[1.0, 0.0, 0.0, 1.0, 0.0, 0.0]] - - for state in states: - best_p = search_nearest_one_from_lookup_table( - state[0], state[1], state[2], lookup_table) - - target = motion_model.State(x=state[0], y=state[1], yaw=state[2]) - init_p = np.array( - [np.hypot(state[0], state[1]), best_p[4], best_p[5]]).reshape(3, 1) - - x, y, yaw, p = trajectory_generator.optimize_trajectory(target, - k0, init_p) - - if x is not None: - print("find good path") - lookup_table.append( - [x[-1], y[-1], yaw[-1], float(p[0, 0]), float(p[1, 0]), float(p[2, 0])]) - - print("finish lookup table generation") - - save_lookup_table("lookup_table.csv", lookup_table) - - for table in lookup_table: - x_c, y_c, yaw_c = motion_model.generate_trajectory( - table[3], table[4], table[5], k0) - plt.plot(x_c, y_c, "-r") - x_c, y_c, yaw_c = motion_model.generate_trajectory( - table[3], -table[4], -table[5], k0) - plt.plot(x_c, y_c, "-r") - - plt.grid(True) - plt.axis("equal") - plt.show() - - print("Done") - - -def main(): - generate_lookup_table() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/ModelPredictiveTrajectoryGenerator/motion_model.py b/PathPlanning/ModelPredictiveTrajectoryGenerator/motion_model.py deleted file mode 100644 index 5ef6d2e23f1..00000000000 --- a/PathPlanning/ModelPredictiveTrajectoryGenerator/motion_model.py +++ /dev/null @@ -1,95 +0,0 @@ -import math -import numpy as np -from scipy.interpolate import interp1d -from utils.angle import angle_mod - -# motion parameter -L = 1.0 # wheel base -ds = 0.1 # course distance -v = 10.0 / 3.6 # velocity [m/s] - - -class State: - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def update(state, v, delta, dt, L): - state.v = v - state.x = state.x + state.v * math.cos(state.yaw) * dt - state.y = state.y + state.v * math.sin(state.yaw) * dt - state.yaw = state.yaw + state.v / L * math.tan(delta) * dt - state.yaw = pi_2_pi(state.yaw) - - return state - - -def generate_trajectory(s, km, kf, k0): - n = s / ds - time = s / v # [s] - - if isinstance(time, type(np.array([]))): - time = time[0] - if isinstance(km, type(np.array([]))): - km = km[0] - if isinstance(kf, type(np.array([]))): - kf = kf[0] - - tk = np.array([0.0, time / 2.0, time]) - kk = np.array([k0, km, kf]) - t = np.arange(0.0, time, time / n) - fkp = interp1d(tk, kk, kind="quadratic") - kp = [fkp(ti) for ti in t] - dt = float(time / n) - - # plt.plot(t, kp) - # plt.show() - - state = State() - x, y, yaw = [state.x], [state.y], [state.yaw] - - for ikp in kp: - state = update(state, v, ikp, dt, L) - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - - return x, y, yaw - - -def generate_last_state(s, km, kf, k0): - n = s / ds - time = s / v # [s] - - if isinstance(n, type(np.array([]))): - n = n[0] - if isinstance(time, type(np.array([]))): - time = time[0] - if isinstance(km, type(np.array([]))): - km = km[0] - if isinstance(kf, type(np.array([]))): - kf = kf[0] - - tk = np.array([0.0, time / 2.0, time]) - kk = np.array([k0, km, kf]) - t = np.arange(0.0, time, time / n) - fkp = interp1d(tk, kk, kind="quadratic") - kp = [fkp(ti) for ti in t] - dt = time / n - - # plt.plot(t, kp) - # plt.show() - - state = State() - - _ = [update(state, v, ikp, dt, L) for ikp in kp] - - return state.x, state.y, state.yaw diff --git a/PathPlanning/ModelPredictiveTrajectoryGenerator/trajectory_generator.py b/PathPlanning/ModelPredictiveTrajectoryGenerator/trajectory_generator.py deleted file mode 100644 index 6084fc1a074..00000000000 --- a/PathPlanning/ModelPredictiveTrajectoryGenerator/trajectory_generator.py +++ /dev/null @@ -1,162 +0,0 @@ -""" - -Model trajectory generator - -author: Atsushi Sakai(@Atsushi_twi) - -""" - -import math -import matplotlib.pyplot as plt -import numpy as np -import sys -import pathlib -path_planning_dir = pathlib.Path(__file__).parent.parent -sys.path.append(str(path_planning_dir)) - -import ModelPredictiveTrajectoryGenerator.motion_model as motion_model - -# optimization parameter -max_iter = 100 -h: np.ndarray = np.array([0.5, 0.02, 0.02]).T # parameter sampling distance -cost_th = 0.1 - -show_animation = True - - -def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"): # pragma: no cover - """ - Plot arrow - """ - plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw), - fc=fc, ec=ec, head_width=width, head_length=width) - plt.plot(x, y) - plt.plot(0, 0) - - -def calc_diff(target, x, y, yaw): - d = np.array([target.x - x[-1], - target.y - y[-1], - motion_model.pi_2_pi(target.yaw - yaw[-1])]) - - return d - - -def calc_j(target, p, h, k0): - xp, yp, yawp = motion_model.generate_last_state( - p[0, 0] + h[0], p[1, 0], p[2, 0], k0) - dp = calc_diff(target, [xp], [yp], [yawp]) - xn, yn, yawn = motion_model.generate_last_state( - p[0, 0] - h[0], p[1, 0], p[2, 0], k0) - dn = calc_diff(target, [xn], [yn], [yawn]) - d1 = np.array((dp - dn) / (2.0 * h[0])).reshape(3, 1) - - xp, yp, yawp = motion_model.generate_last_state( - p[0, 0], p[1, 0] + h[1], p[2, 0], k0) - dp = calc_diff(target, [xp], [yp], [yawp]) - xn, yn, yawn = motion_model.generate_last_state( - p[0, 0], p[1, 0] - h[1], p[2, 0], k0) - dn = calc_diff(target, [xn], [yn], [yawn]) - d2 = np.array((dp - dn) / (2.0 * h[1])).reshape(3, 1) - - xp, yp, yawp = motion_model.generate_last_state( - p[0, 0], p[1, 0], p[2, 0] + h[2], k0) - dp = calc_diff(target, [xp], [yp], [yawp]) - xn, yn, yawn = motion_model.generate_last_state( - p[0, 0], p[1, 0], p[2, 0] - h[2], k0) - dn = calc_diff(target, [xn], [yn], [yawn]) - d3 = np.array((dp - dn) / (2.0 * h[2])).reshape(3, 1) - - J = np.hstack((d1, d2, d3)) - - return J - - -def selection_learning_param(dp, p, k0, target): - mincost = float("inf") - mina = 1.0 - maxa = 2.0 - da = 0.5 - - for a in np.arange(mina, maxa, da): - tp = p + a * dp - xc, yc, yawc = motion_model.generate_last_state( - tp[0], tp[1], tp[2], k0) - dc = calc_diff(target, [xc], [yc], [yawc]) - cost = np.linalg.norm(dc) - - if cost <= mincost and a != 0.0: - mina = a - mincost = cost - - # print(mincost, mina) - # input() - - return mina - - -def show_trajectory(target, xc, yc): # pragma: no cover - plt.clf() - plot_arrow(target.x, target.y, target.yaw) - plt.plot(xc, yc, "-r") - plt.axis("equal") - plt.grid(True) - plt.pause(0.1) - - -def optimize_trajectory(target, k0, p): - for i in range(max_iter): - xc, yc, yawc = motion_model.generate_trajectory(p[0, 0], p[1, 0], p[2, 0], k0) - dc = np.array(calc_diff(target, xc, yc, yawc)).reshape(3, 1) - - cost = np.linalg.norm(dc) - if cost <= cost_th: - print("path is ok cost is:" + str(cost)) - break - - J = calc_j(target, p, h, k0) - try: - dp = - np.linalg.inv(J) @ dc - except np.linalg.linalg.LinAlgError: - print("cannot calc path LinAlgError") - xc, yc, yawc, p = None, None, None, None - break - alpha = selection_learning_param(dp, p, k0, target) - - p += alpha * np.array(dp) - # print(p.T) - - if show_animation: # pragma: no cover - show_trajectory(target, xc, yc) - else: - xc, yc, yawc, p = None, None, None, None - print("cannot calc path") - - return xc, yc, yawc, p - - -def optimize_trajectory_demo(): # pragma: no cover - - # target = motion_model.State(x=5.0, y=2.0, yaw=np.deg2rad(00.0)) - target = motion_model.State(x=5.0, y=2.0, yaw=np.deg2rad(90.0)) - k0 = 0.0 - - init_p = np.array([6.0, 0.0, 0.0]).reshape(3, 1) - - x, y, yaw, p = optimize_trajectory(target, k0, init_p) - - if show_animation: - show_trajectory(target, x, y) - plot_arrow(target.x, target.y, target.yaw) - plt.axis("equal") - plt.grid(True) - plt.show() - - -def main(): # pragma: no cover - print(__file__ + " start!!") - optimize_trajectory_demo() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/PotentialFieldPlanning/potential_field_planning.py b/PathPlanning/PotentialFieldPlanning/potential_field_planning.py deleted file mode 100644 index 8f136b5ee3f..00000000000 --- a/PathPlanning/PotentialFieldPlanning/potential_field_planning.py +++ /dev/null @@ -1,199 +0,0 @@ -""" - -Potential Field based path planner - -author: Atsushi Sakai (@Atsushi_twi) - -Ref: -https://www.cs.cmu.edu/~motionplanning/lecture/Chap4-Potential-Field_howie.pdf - -""" - -from collections import deque -import numpy as np -import matplotlib.pyplot as plt - -# Parameters -KP = 5.0 # attractive potential gain -ETA = 100.0 # repulsive potential gain -AREA_WIDTH = 30.0 # potential area width [m] -# the number of previous positions used to check oscillations -OSCILLATIONS_DETECTION_LENGTH = 3 - -show_animation = True - - -def calc_potential_field(gx, gy, ox, oy, reso, rr, sx, sy): - minx = min(min(ox), sx, gx) - AREA_WIDTH / 2.0 - miny = min(min(oy), sy, gy) - AREA_WIDTH / 2.0 - maxx = max(max(ox), sx, gx) + AREA_WIDTH / 2.0 - maxy = max(max(oy), sy, gy) + AREA_WIDTH / 2.0 - xw = int(round((maxx - minx) / reso)) - yw = int(round((maxy - miny) / reso)) - - # calc each potential - pmap = [[0.0 for i in range(yw)] for i in range(xw)] - - for ix in range(xw): - x = ix * reso + minx - - for iy in range(yw): - y = iy * reso + miny - ug = calc_attractive_potential(x, y, gx, gy) - uo = calc_repulsive_potential(x, y, ox, oy, rr) - uf = ug + uo - pmap[ix][iy] = uf - - return pmap, minx, miny - - -def calc_attractive_potential(x, y, gx, gy): - return 0.5 * KP * np.hypot(x - gx, y - gy) - - -def calc_repulsive_potential(x, y, ox, oy, rr): - # search nearest obstacle - minid = -1 - dmin = float("inf") - for i, _ in enumerate(ox): - d = np.hypot(x - ox[i], y - oy[i]) - if dmin >= d: - dmin = d - minid = i - - # calc repulsive potential - dq = np.hypot(x - ox[minid], y - oy[minid]) - - if dq <= rr: - if dq <= 0.1: - dq = 0.1 - - return 0.5 * ETA * (1.0 / dq - 1.0 / rr) ** 2 - else: - return 0.0 - - -def get_motion_model(): - # dx, dy - motion = [[1, 0], - [0, 1], - [-1, 0], - [0, -1], - [-1, -1], - [-1, 1], - [1, -1], - [1, 1]] - - return motion - - -def oscillations_detection(previous_ids, ix, iy): - previous_ids.append((ix, iy)) - - if (len(previous_ids) > OSCILLATIONS_DETECTION_LENGTH): - previous_ids.popleft() - - # check if contains any duplicates by copying into a set - previous_ids_set = set() - for index in previous_ids: - if index in previous_ids_set: - return True - else: - previous_ids_set.add(index) - return False - - -def potential_field_planning(sx, sy, gx, gy, ox, oy, reso, rr): - - # calc potential field - pmap, minx, miny = calc_potential_field(gx, gy, ox, oy, reso, rr, sx, sy) - - # search path - d = np.hypot(sx - gx, sy - gy) - ix = round((sx - minx) / reso) - iy = round((sy - miny) / reso) - gix = round((gx - minx) / reso) - giy = round((gy - miny) / reso) - - if show_animation: - draw_heatmap(pmap) - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(ix, iy, "*k") - plt.plot(gix, giy, "*m") - - rx, ry = [sx], [sy] - motion = get_motion_model() - previous_ids = deque() - - while d >= reso: - minp = float("inf") - minix, miniy = -1, -1 - for i, _ in enumerate(motion): - inx = int(ix + motion[i][0]) - iny = int(iy + motion[i][1]) - if inx >= len(pmap) or iny >= len(pmap[0]) or inx < 0 or iny < 0: - p = float("inf") # outside area - print("outside potential!") - else: - p = pmap[inx][iny] - if minp > p: - minp = p - minix = inx - miniy = iny - ix = minix - iy = miniy - xp = ix * reso + minx - yp = iy * reso + miny - d = np.hypot(gx - xp, gy - yp) - rx.append(xp) - ry.append(yp) - - if (oscillations_detection(previous_ids, ix, iy)): - print("Oscillation detected at ({},{})!".format(ix, iy)) - break - - if show_animation: - plt.plot(ix, iy, ".r") - plt.pause(0.01) - - print("Goal!!") - - return rx, ry - - -def draw_heatmap(data): - data = np.array(data).T - plt.pcolor(data, vmax=100.0, cmap=plt.cm.Blues) - - -def main(): - print("potential_field_planning start") - - sx = 0.0 # start x position [m] - sy = 10.0 # start y positon [m] - gx = 30.0 # goal x position [m] - gy = 30.0 # goal y position [m] - grid_size = 0.5 # potential grid size [m] - robot_radius = 5.0 # robot radius [m] - - ox = [15.0, 5.0, 20.0, 25.0] # obstacle x position list [m] - oy = [25.0, 15.0, 26.0, 25.0] # obstacle y position list [m] - - if show_animation: - plt.grid(True) - plt.axis("equal") - - # path generation - _, _ = potential_field_planning( - sx, sy, gx, gy, ox, oy, grid_size, robot_radius) - - if show_animation: - plt.show() - - -if __name__ == '__main__': - print(__file__ + " start!!") - main() - print(__file__ + " Done!!") diff --git a/PathPlanning/ProbabilisticRoadMap/probabilistic_road_map.py b/PathPlanning/ProbabilisticRoadMap/probabilistic_road_map.py deleted file mode 100644 index 8bacfd5d199..00000000000 --- a/PathPlanning/ProbabilisticRoadMap/probabilistic_road_map.py +++ /dev/null @@ -1,312 +0,0 @@ -""" - -Probabilistic Road Map (PRM) Planner - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math -import numpy as np -import matplotlib.pyplot as plt -from scipy.spatial import KDTree - -# parameter -N_SAMPLE = 500 # number of sample_points -N_KNN = 10 # number of edge from one sampled point -MAX_EDGE_LEN = 30.0 # [m] Maximum edge length - -show_animation = True - - -class Node: - """ - Node class for dijkstra search - """ - - def __init__(self, x, y, cost, parent_index): - self.x = x - self.y = y - self.cost = cost - self.parent_index = parent_index - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," +\ - str(self.cost) + "," + str(self.parent_index) - - -def prm_planning(start_x, start_y, goal_x, goal_y, - obstacle_x_list, obstacle_y_list, robot_radius, *, rng=None): - """ - Run probabilistic road map planning - - :param start_x: start x position - :param start_y: start y position - :param goal_x: goal x position - :param goal_y: goal y position - :param obstacle_x_list: obstacle x positions - :param obstacle_y_list: obstacle y positions - :param robot_radius: robot radius - :param rng: (Optional) Random generator - :return: - """ - obstacle_kd_tree = KDTree(np.vstack((obstacle_x_list, obstacle_y_list)).T) - - sample_x, sample_y = sample_points(start_x, start_y, goal_x, goal_y, - robot_radius, - obstacle_x_list, obstacle_y_list, - obstacle_kd_tree, rng) - if show_animation: - plt.plot(sample_x, sample_y, ".b") - - road_map = generate_road_map(sample_x, sample_y, - robot_radius, obstacle_kd_tree) - - rx, ry = dijkstra_planning( - start_x, start_y, goal_x, goal_y, road_map, sample_x, sample_y) - - return rx, ry - - -def is_collision(sx, sy, gx, gy, rr, obstacle_kd_tree): - x = sx - y = sy - dx = gx - sx - dy = gy - sy - yaw = math.atan2(gy - sy, gx - sx) - d = math.hypot(dx, dy) - - if d >= MAX_EDGE_LEN: - return True - - D = rr - n_step = round(d / D) - - for i in range(n_step): - dist, _ = obstacle_kd_tree.query([x, y]) - if dist <= rr: - return True # collision - x += D * math.cos(yaw) - y += D * math.sin(yaw) - - # goal point check - dist, _ = obstacle_kd_tree.query([gx, gy]) - if dist <= rr: - return True # collision - - return False # OK - - -def generate_road_map(sample_x, sample_y, rr, obstacle_kd_tree): - """ - Road map generation - - sample_x: [m] x positions of sampled points - sample_y: [m] y positions of sampled points - robot_radius: Robot Radius[m] - obstacle_kd_tree: KDTree object of obstacles - """ - - road_map = [] - n_sample = len(sample_x) - sample_kd_tree = KDTree(np.vstack((sample_x, sample_y)).T) - - for (i, ix, iy) in zip(range(n_sample), sample_x, sample_y): - - dists, indexes = sample_kd_tree.query([ix, iy], k=n_sample) - edge_id = [] - - for ii in range(1, len(indexes)): - nx = sample_x[indexes[ii]] - ny = sample_y[indexes[ii]] - - if not is_collision(ix, iy, nx, ny, rr, obstacle_kd_tree): - edge_id.append(indexes[ii]) - - if len(edge_id) >= N_KNN: - break - - road_map.append(edge_id) - - # plot_road_map(road_map, sample_x, sample_y) - - return road_map - - -def dijkstra_planning(sx, sy, gx, gy, road_map, sample_x, sample_y): - """ - s_x: start x position [m] - s_y: start y position [m] - goal_x: goal x position [m] - goal_y: goal y position [m] - obstacle_x_list: x position list of Obstacles [m] - obstacle_y_list: y position list of Obstacles [m] - robot_radius: robot radius [m] - road_map: ??? [m] - sample_x: ??? [m] - sample_y: ??? [m] - - @return: Two lists of path coordinates ([x1, x2, ...], [y1, y2, ...]), empty list when no path was found - """ - - start_node = Node(sx, sy, 0.0, -1) - goal_node = Node(gx, gy, 0.0, -1) - - open_set, closed_set = dict(), dict() - open_set[len(road_map) - 2] = start_node - - path_found = True - - while True: - if not open_set: - print("Cannot find path") - path_found = False - break - - c_id = min(open_set, key=lambda o: open_set[o].cost) - current = open_set[c_id] - - # show graph - if show_animation and len(closed_set.keys()) % 2 == 0: - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(current.x, current.y, "xg") - plt.pause(0.001) - - if c_id == (len(road_map) - 1): - print("goal is found!") - goal_node.parent_index = current.parent_index - goal_node.cost = current.cost - break - - # Remove the item from the open set - del open_set[c_id] - # Add it to the closed set - closed_set[c_id] = current - - # expand search grid based on motion model - for i in range(len(road_map[c_id])): - n_id = road_map[c_id][i] - dx = sample_x[n_id] - current.x - dy = sample_y[n_id] - current.y - d = math.hypot(dx, dy) - node = Node(sample_x[n_id], sample_y[n_id], - current.cost + d, c_id) - - if n_id in closed_set: - continue - # Otherwise if it is already in the open set - if n_id in open_set: - if open_set[n_id].cost > node.cost: - open_set[n_id].cost = node.cost - open_set[n_id].parent_index = c_id - else: - open_set[n_id] = node - - if path_found is False: - return [], [] - - # generate final course - rx, ry = [goal_node.x], [goal_node.y] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_set[parent_index] - rx.append(n.x) - ry.append(n.y) - parent_index = n.parent_index - - return rx, ry - - -def plot_road_map(road_map, sample_x, sample_y): # pragma: no cover - - for i, _ in enumerate(road_map): - for ii in range(len(road_map[i])): - ind = road_map[i][ii] - - plt.plot([sample_x[i], sample_x[ind]], - [sample_y[i], sample_y[ind]], "-k") - - -def sample_points(sx, sy, gx, gy, rr, ox, oy, obstacle_kd_tree, rng): - max_x = max(ox) - max_y = max(oy) - min_x = min(ox) - min_y = min(oy) - - sample_x, sample_y = [], [] - - if rng is None: - rng = np.random.default_rng() - - while len(sample_x) <= N_SAMPLE: - tx = (rng.random() * (max_x - min_x)) + min_x - ty = (rng.random() * (max_y - min_y)) + min_y - - dist, index = obstacle_kd_tree.query([tx, ty]) - - if dist >= rr: - sample_x.append(tx) - sample_y.append(ty) - - sample_x.append(sx) - sample_y.append(sy) - sample_x.append(gx) - sample_y.append(gy) - - return sample_x, sample_y - - -def main(rng=None): - print(__file__ + " start!!") - - # start and goal position - sx = 10.0 # [m] - sy = 10.0 # [m] - gx = 50.0 # [m] - gy = 50.0 # [m] - robot_size = 5.0 # [m] - - ox = [] - oy = [] - - for i in range(60): - ox.append(float(i)) - oy.append(0.0) - for i in range(60): - ox.append(60.0) - oy.append(float(i)) - for i in range(61): - ox.append(float(i)) - oy.append(60.0) - for i in range(61): - ox.append(0.0) - oy.append(float(i)) - for i in range(40): - ox.append(20.0) - oy.append(float(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, "^r") - plt.plot(gx, gy, "^c") - plt.grid(True) - plt.axis("equal") - - rx, ry = prm_planning(sx, sy, gx, gy, ox, oy, robot_size, rng=rng) - - assert rx, 'Cannot found path' - - if show_animation: - plt.plot(rx, ry, "-r") - plt.pause(0.001) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/QuinticPolynomialsPlanner/quintic_polynomials_planner.py b/PathPlanning/QuinticPolynomialsPlanner/quintic_polynomials_planner.py deleted file mode 100644 index fdc181afab9..00000000000 --- a/PathPlanning/QuinticPolynomialsPlanner/quintic_polynomials_planner.py +++ /dev/null @@ -1,230 +0,0 @@ -""" - -Quintic Polynomials Planner - -author: Atsushi Sakai (@Atsushi_twi) - -Ref: - -- [Local Path planning And Motion Control For Agv In Positioning](https://ieeexplore.ieee.org/document/637936/) - -""" - -import math - -import matplotlib.pyplot as plt -import numpy as np - -# parameter -MAX_T = 100.0 # maximum time to the goal [s] -MIN_T = 5.0 # minimum time to the goal[s] - -show_animation = True - - -class QuinticPolynomial: - - def __init__(self, xs, vxs, axs, xe, vxe, axe, time): - # calc coefficient of quintic polynomial - # See jupyter notebook document for derivation of this equation. - self.a0 = xs - self.a1 = vxs - self.a2 = axs / 2.0 - - A = np.array([[time ** 3, time ** 4, time ** 5], - [3 * time ** 2, 4 * time ** 3, 5 * time ** 4], - [6 * time, 12 * time ** 2, 20 * time ** 3]]) - b = np.array([xe - self.a0 - self.a1 * time - self.a2 * time ** 2, - vxe - self.a1 - 2 * self.a2 * time, - axe - 2 * self.a2]) - x = np.linalg.solve(A, b) - - self.a3 = x[0] - self.a4 = x[1] - self.a5 = x[2] - - def calc_point(self, t): - xt = self.a0 + self.a1 * t + self.a2 * t ** 2 + \ - self.a3 * t ** 3 + self.a4 * t ** 4 + self.a5 * t ** 5 - - return xt - - def calc_first_derivative(self, t): - xt = self.a1 + 2 * self.a2 * t + \ - 3 * self.a3 * t ** 2 + 4 * self.a4 * t ** 3 + 5 * self.a5 * t ** 4 - - return xt - - def calc_second_derivative(self, t): - xt = 2 * self.a2 + 6 * self.a3 * t + 12 * self.a4 * t ** 2 + 20 * self.a5 * t ** 3 - - return xt - - def calc_third_derivative(self, t): - xt = 6 * self.a3 + 24 * self.a4 * t + 60 * self.a5 * t ** 2 - - return xt - - -def quintic_polynomials_planner(sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt): - """ - quintic polynomial planner - - input - s_x: start x position [m] - s_y: start y position [m] - s_yaw: start yaw angle [rad] - sa: start accel [m/ss] - gx: goal x position [m] - gy: goal y position [m] - gyaw: goal yaw angle [rad] - ga: goal accel [m/ss] - max_accel: maximum accel [m/ss] - max_jerk: maximum jerk [m/sss] - dt: time tick [s] - - return - time: time result - rx: x position result list - ry: y position result list - ryaw: yaw angle result list - rv: velocity result list - ra: accel result list - - """ - - vxs = sv * math.cos(syaw) - vys = sv * math.sin(syaw) - vxg = gv * math.cos(gyaw) - vyg = gv * math.sin(gyaw) - - axs = sa * math.cos(syaw) - ays = sa * math.sin(syaw) - axg = ga * math.cos(gyaw) - ayg = ga * math.sin(gyaw) - - time, rx, ry, ryaw, rv, ra, rj = [], [], [], [], [], [], [] - - for T in np.arange(MIN_T, MAX_T, MIN_T): - xqp = QuinticPolynomial(sx, vxs, axs, gx, vxg, axg, T) - yqp = QuinticPolynomial(sy, vys, ays, gy, vyg, ayg, T) - - time, rx, ry, ryaw, rv, ra, rj = [], [], [], [], [], [], [] - - for t in np.arange(0.0, T + dt, dt): - time.append(t) - rx.append(xqp.calc_point(t)) - ry.append(yqp.calc_point(t)) - - vx = xqp.calc_first_derivative(t) - vy = yqp.calc_first_derivative(t) - v = np.hypot(vx, vy) - yaw = math.atan2(vy, vx) - rv.append(v) - ryaw.append(yaw) - - ax = xqp.calc_second_derivative(t) - ay = yqp.calc_second_derivative(t) - a = np.hypot(ax, ay) - if len(rv) >= 2 and rv[-1] - rv[-2] < 0.0: - a *= -1 - ra.append(a) - - jx = xqp.calc_third_derivative(t) - jy = yqp.calc_third_derivative(t) - j = np.hypot(jx, jy) - if len(ra) >= 2 and ra[-1] - ra[-2] < 0.0: - j *= -1 - rj.append(j) - - if max([abs(i) for i in ra]) <= max_accel and max([abs(i) for i in rj]) <= max_jerk: - print("find path!!") - break - - if show_animation: # pragma: no cover - for i, _ in enumerate(time): - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.grid(True) - plt.axis("equal") - plot_arrow(sx, sy, syaw) - plot_arrow(gx, gy, gyaw) - plot_arrow(rx[i], ry[i], ryaw[i]) - plt.title("Time[s]:" + str(time[i])[0:4] + - " v[m/s]:" + str(rv[i])[0:4] + - " a[m/ss]:" + str(ra[i])[0:4] + - " jerk[m/sss]:" + str(rj[i])[0:4], - ) - plt.pause(0.001) - - return time, rx, ry, ryaw, rv, ra, rj - - -def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"): # pragma: no cover - """ - Plot arrow - """ - - if not isinstance(x, float): - for (ix, iy, iyaw) in zip(x, y, yaw): - plot_arrow(ix, iy, iyaw) - else: - plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw), - fc=fc, ec=ec, head_width=width, head_length=width) - plt.plot(x, y) - - -def main(): - print(__file__ + " start!!") - - sx = 10.0 # start x position [m] - sy = 10.0 # start y position [m] - syaw = np.deg2rad(10.0) # start yaw angle [rad] - sv = 1.0 # start speed [m/s] - sa = 0.1 # start accel [m/ss] - gx = 30.0 # goal x position [m] - gy = -10.0 # goal y position [m] - gyaw = np.deg2rad(20.0) # goal yaw angle [rad] - gv = 1.0 # goal speed [m/s] - ga = 0.1 # goal accel [m/ss] - max_accel = 1.0 # max accel [m/ss] - max_jerk = 0.5 # max jerk [m/sss] - dt = 0.1 # time tick [s] - - time, x, y, yaw, v, a, j = quintic_polynomials_planner( - sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt) - - if show_animation: # pragma: no cover - plt.plot(x, y, "-r") - - plt.subplots() - plt.plot(time, [np.rad2deg(i) for i in yaw], "-r") - plt.xlabel("Time[s]") - plt.ylabel("Yaw[deg]") - plt.grid(True) - - plt.subplots() - plt.plot(time, v, "-r") - plt.xlabel("Time[s]") - plt.ylabel("Speed[m/s]") - plt.grid(True) - - plt.subplots() - plt.plot(time, a, "-r") - plt.xlabel("Time[s]") - plt.ylabel("accel[m/ss]") - plt.grid(True) - - plt.subplots() - plt.plot(time, j, "-r") - plt.xlabel("Time[s]") - plt.ylabel("jerk[m/sss]") - plt.grid(True) - - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRT/__init__.py b/PathPlanning/RRT/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/RRT/rrt.py b/PathPlanning/RRT/rrt.py deleted file mode 100644 index e6dd9b648b5..00000000000 --- a/PathPlanning/RRT/rrt.py +++ /dev/null @@ -1,291 +0,0 @@ -""" - -Path planning Sample Code with Randomized Rapidly-Exploring Random Trees (RRT) - -author: AtsushiSakai(@Atsushi_twi) - -""" - -import math -import random - -import matplotlib.pyplot as plt -import numpy as np - -show_animation = True - - -class RRT: - """ - Class for RRT planning - """ - - class Node: - """ - RRT Node - """ - - def __init__(self, x, y): - self.x = x - self.y = y - self.path_x = [] - self.path_y = [] - self.parent = None - - class AreaBounds: - - def __init__(self, area): - self.xmin = float(area[0]) - self.xmax = float(area[1]) - self.ymin = float(area[2]) - self.ymax = float(area[3]) - - - def __init__(self, - start, - goal, - obstacle_list, - rand_area, - expand_dis=3.0, - path_resolution=0.5, - goal_sample_rate=5, - max_iter=500, - play_area=None, - robot_radius=0.0, - ): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacleList:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - play_area:stay inside this area [xmin,xmax,ymin,ymax] - robot_radius: robot body modeled as circle with given radius - - """ - self.start = self.Node(start[0], start[1]) - self.end = self.Node(goal[0], goal[1]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - if play_area is not None: - self.play_area = self.AreaBounds(play_area) - else: - self.play_area = None - self.expand_dis = expand_dis - self.path_resolution = path_resolution - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.obstacle_list = obstacle_list - self.node_list = [] - self.robot_radius = robot_radius - - def planning(self, animation=True): - """ - rrt path planning - - animation: flag for animation on or off - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - rnd_node = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd_node) - nearest_node = self.node_list[nearest_ind] - - new_node = self.steer(nearest_node, rnd_node, self.expand_dis) - - if self.check_if_outside_play_area(new_node, self.play_area) and \ - self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - self.node_list.append(new_node) - - if animation and i % 5 == 0: - self.draw_graph(rnd_node) - - if self.calc_dist_to_goal(self.node_list[-1].x, - self.node_list[-1].y) <= self.expand_dis: - final_node = self.steer(self.node_list[-1], self.end, - self.expand_dis) - if self.check_collision( - final_node, self.obstacle_list, self.robot_radius): - return self.generate_final_course(len(self.node_list) - 1) - - if animation and i % 5: - self.draw_graph(rnd_node) - - return None # cannot find path - - def steer(self, from_node, to_node, extend_length=float("inf")): - - new_node = self.Node(from_node.x, from_node.y) - d, theta = self.calc_distance_and_angle(new_node, to_node) - - new_node.path_x = [new_node.x] - new_node.path_y = [new_node.y] - - if extend_length > d: - extend_length = d - - n_expand = math.floor(extend_length / self.path_resolution) - - for _ in range(n_expand): - new_node.x += self.path_resolution * math.cos(theta) - new_node.y += self.path_resolution * math.sin(theta) - new_node.path_x.append(new_node.x) - new_node.path_y.append(new_node.y) - - d, _ = self.calc_distance_and_angle(new_node, to_node) - if d <= self.path_resolution: - new_node.path_x.append(to_node.x) - new_node.path_y.append(to_node.y) - new_node.x = to_node.x - new_node.y = to_node.y - - new_node.parent = from_node - - return new_node - - def generate_final_course(self, goal_ind): - path = [[self.end.x, self.end.y]] - node = self.node_list[goal_ind] - while node.parent is not None: - path.append([node.x, node.y]) - node = node.parent - path.append([node.x, node.y]) - - return path - - def calc_dist_to_goal(self, x, y): - dx = x - self.end.x - dy = y - self.end.y - return math.hypot(dx, dy) - - def get_random_node(self): - if random.randint(0, 100) > self.goal_sample_rate: - rnd = self.Node( - random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand)) - else: # goal point sampling - rnd = self.Node(self.end.x, self.end.y) - return rnd - - def draw_graph(self, rnd=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd.x, rnd.y, "^k") - if self.robot_radius > 0.0: - self.plot_circle(rnd.x, rnd.y, self.robot_radius, '-r') - for node in self.node_list: - if node.parent: - plt.plot(node.path_x, node.path_y, "-g") - - for (ox, oy, size) in self.obstacle_list: - self.plot_circle(ox, oy, size) - - if self.play_area is not None: - plt.plot([self.play_area.xmin, self.play_area.xmax, - self.play_area.xmax, self.play_area.xmin, - self.play_area.xmin], - [self.play_area.ymin, self.play_area.ymin, - self.play_area.ymax, self.play_area.ymax, - self.play_area.ymin], - "-k") - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.end.x, self.end.y, "xr") - plt.axis("equal") - plt.axis([self.min_rand, self.max_rand, self.min_rand, self.max_rand]) - plt.grid(True) - plt.pause(0.01) - - @staticmethod - def plot_circle(x, y, size, color="-b"): # pragma: no cover - deg = list(range(0, 360, 5)) - deg.append(0) - xl = [x + size * math.cos(np.deg2rad(d)) for d in deg] - yl = [y + size * math.sin(np.deg2rad(d)) for d in deg] - plt.plot(xl, yl, color) - - @staticmethod - def get_nearest_node_index(node_list, rnd_node): - dlist = [(node.x - rnd_node.x)**2 + (node.y - rnd_node.y)**2 - for node in node_list] - minind = dlist.index(min(dlist)) - - return minind - - @staticmethod - def check_if_outside_play_area(node, play_area): - - if play_area is None: - return True # no play_area was defined, every pos should be ok - - if node.x < play_area.xmin or node.x > play_area.xmax or \ - node.y < play_area.ymin or node.y > play_area.ymax: - return False # outside - bad - else: - return True # inside - ok - - @staticmethod - def check_collision(node, obstacleList, robot_radius): - - if node is None: - return False - - for (ox, oy, size) in obstacleList: - dx_list = [ox - x for x in node.path_x] - dy_list = [oy - y for y in node.path_y] - d_list = [dx * dx + dy * dy for (dx, dy) in zip(dx_list, dy_list)] - - if min(d_list) <= (size+robot_radius)**2: - return False # collision - - return True # safe - - @staticmethod - def calc_distance_and_angle(from_node, to_node): - dx = to_node.x - from_node.x - dy = to_node.y - from_node.y - d = math.hypot(dx, dy) - theta = math.atan2(dy, dx) - return d, theta - - -def main(gx=6.0, gy=10.0): - print("start " + __file__) - - # ====Search Path with RRT==== - obstacleList = [(5, 5, 1), (3, 6, 2), (3, 8, 2), (3, 10, 2), (7, 5, 2), - (9, 5, 2), (8, 10, 1)] # [x, y, radius] - # Set Initial parameters - rrt = RRT( - start=[0, 0], - goal=[gx, gy], - rand_area=[-2, 15], - obstacle_list=obstacleList, - # play_area=[0, 10, 0, 14] - robot_radius=0.8 - ) - path = rrt.planning(animation=show_animation) - - if path is None: - print("Cannot find path") - else: - print("found path!!") - - # Draw final path - if show_animation: - rrt.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.01) # Need for Mac - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRT/rrt_with_pathsmoothing.py b/PathPlanning/RRT/rrt_with_pathsmoothing.py deleted file mode 100644 index 2ed6a366d15..00000000000 --- a/PathPlanning/RRT/rrt_with_pathsmoothing.py +++ /dev/null @@ -1,145 +0,0 @@ -""" - -Path planning Sample Code with RRT with path smoothing - -@author: AtsushiSakai(@Atsushi_twi) - -""" - -import math -import random -import matplotlib.pyplot as plt -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent)) - -from rrt import RRT - -show_animation = True - - -def get_path_length(path): - le = 0 - for i in range(len(path) - 1): - dx = path[i + 1][0] - path[i][0] - dy = path[i + 1][1] - path[i][1] - d = math.hypot(dx, dy) - le += d - - return le - - -def get_target_point(path, targetL): - le = 0 - ti = 0 - lastPairLen = 0 - for i in range(len(path) - 1): - dx = path[i + 1][0] - path[i][0] - dy = path[i + 1][1] - path[i][1] - d = math.hypot(dx, dy) - le += d - if le >= targetL: - ti = i - 1 - lastPairLen = d - break - - partRatio = (le - targetL) / lastPairLen - - x = path[ti][0] + (path[ti + 1][0] - path[ti][0]) * partRatio - y = path[ti][1] + (path[ti + 1][1] - path[ti][1]) * partRatio - - return [x, y, ti] - - -def line_collision_check(first, second, obstacleList): - # Line Equation - - x1 = first[0] - y1 = first[1] - x2 = second[0] - y2 = second[1] - - try: - a = y2 - y1 - b = -(x2 - x1) - c = y2 * (x2 - x1) - x2 * (y2 - y1) - except ZeroDivisionError: - return False - - for (ox, oy, size) in obstacleList: - d = abs(a * ox + b * oy + c) / (math.hypot(a, b)) - if d <= size: - return False - - return True # OK - - -def path_smoothing(path, max_iter, obstacle_list): - le = get_path_length(path) - - for i in range(max_iter): - # Sample two points - pickPoints = [random.uniform(0, le), random.uniform(0, le)] - pickPoints.sort() - first = get_target_point(path, pickPoints[0]) - second = get_target_point(path, pickPoints[1]) - - if first[2] <= 0 or second[2] <= 0: - continue - - if (second[2] + 1) > len(path): - continue - - if second[2] == first[2]: - continue - - # collision check - if not line_collision_check(first, second, obstacle_list): - continue - - # Create New path - newPath = [] - newPath.extend(path[:first[2] + 1]) - newPath.append([first[0], first[1]]) - newPath.append([second[0], second[1]]) - newPath.extend(path[second[2] + 1:]) - path = newPath - le = get_path_length(path) - - return path - - -def main(): - # ====Search Path with RRT==== - # Parameter - obstacleList = [ - (5, 5, 1), - (3, 6, 2), - (3, 8, 2), - (3, 10, 2), - (7, 5, 2), - (9, 5, 2) - ] # [x,y,size] - rrt = RRT(start=[0, 0], goal=[6, 10], - rand_area=[-2, 15], obstacle_list=obstacleList) - path = rrt.planning(animation=show_animation) - - # Path smoothing - maxIter = 1000 - smoothedPath = path_smoothing(path, maxIter, obstacleList) - - # Draw final path - if show_animation: - rrt.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - - plt.plot([x for (x, y) in smoothedPath], [ - y for (x, y) in smoothedPath], '-c') - - plt.grid(True) - plt.pause(0.01) # Need for Mac - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRT/rrt_with_sobol_sampler.py b/PathPlanning/RRT/rrt_with_sobol_sampler.py deleted file mode 100644 index 06e0c04c683..00000000000 --- a/PathPlanning/RRT/rrt_with_sobol_sampler.py +++ /dev/null @@ -1,278 +0,0 @@ -""" - -Path planning Sample Code with Randomized Rapidly-Exploring Random -Trees with sobol low discrepancy sampler(RRTSobol). -Sobol wiki https://en.wikipedia.org/wiki/Sobol_sequence - -The goal of low discrepancy samplers is to generate a sequence of points that -optimizes a criterion called dispersion. Intuitively, the idea is to place -samples to cover the exploration space in a way that makes the largest -uncovered area be as small as possible. This generalizes of the idea of grid -resolution. For a grid, the resolution may be selected by defining the step -size for each axis. As the step size is decreased, the resolution increases. -If a grid-based motion planning algorithm can increase the resolution -arbitrarily, it becomes resolution complete. Dispersion can be considered as a -powerful generalization of the notion of resolution. - -Taken from -LaValle, Steven M. Planning algorithms. Cambridge university press, 2006. - - -authors: - First implementation AtsushiSakai(@Atsushi_twi) - Sobol sampler Rafael A. -Rojas (rafaelrojasmiliani@gmail.com) - - -""" - -import math -import random -import sys -import matplotlib.pyplot as plt -import numpy as np - -from sobol import sobol_quasirand - -show_animation = True - - -class RRTSobol: - """ - Class for RRTSobol planning - """ - - class Node: - """ - RRTSobol Node - """ - - def __init__(self, x, y): - self.x = x - self.y = y - self.path_x = [] - self.path_y = [] - self.parent = None - - def __init__(self, - start, - goal, - obstacle_list, - rand_area, - expand_dis=3.0, - path_resolution=0.5, - goal_sample_rate=5, - max_iter=500, - robot_radius=0.0): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacle_list:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - robot_radius: robot body modeled as circle with given radius - - """ - self.start = self.Node(start[0], start[1]) - self.end = self.Node(goal[0], goal[1]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.expand_dis = expand_dis - self.path_resolution = path_resolution - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.obstacle_list = obstacle_list - self.node_list = [] - self.sobol_inter_ = 0 - self.robot_radius = robot_radius - - def planning(self, animation=True): - """ - rrt path planning - - animation: flag for animation on or off - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - rnd_node = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd_node) - nearest_node = self.node_list[nearest_ind] - - new_node = self.steer(nearest_node, rnd_node, self.expand_dis) - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - self.node_list.append(new_node) - - if animation and i % 5 == 0: - self.draw_graph(rnd_node) - - if self.calc_dist_to_goal(self.node_list[-1].x, - self.node_list[-1].y) <= self.expand_dis: - final_node = self.steer(self.node_list[-1], self.end, - self.expand_dis) - if self.check_collision( - final_node, self.obstacle_list, self.robot_radius): - return self.generate_final_course(len(self.node_list) - 1) - - if animation and i % 5: - self.draw_graph(rnd_node) - - return None # cannot find path - - def steer(self, from_node, to_node, extend_length=float("inf")): - - new_node = self.Node(from_node.x, from_node.y) - d, theta = self.calc_distance_and_angle(new_node, to_node) - - new_node.path_x = [new_node.x] - new_node.path_y = [new_node.y] - - if extend_length > d: - extend_length = d - - n_expand = math.floor(extend_length / self.path_resolution) - - for _ in range(n_expand): - new_node.x += self.path_resolution * math.cos(theta) - new_node.y += self.path_resolution * math.sin(theta) - new_node.path_x.append(new_node.x) - new_node.path_y.append(new_node.y) - - d, _ = self.calc_distance_and_angle(new_node, to_node) - if d <= self.path_resolution: - new_node.path_x.append(to_node.x) - new_node.path_y.append(to_node.y) - new_node.x = to_node.x - new_node.y = to_node.y - - new_node.parent = from_node - - return new_node - - def generate_final_course(self, goal_ind): - path = [[self.end.x, self.end.y]] - node = self.node_list[goal_ind] - while node.parent is not None: - path.append([node.x, node.y]) - node = node.parent - path.append([node.x, node.y]) - - return path - - def calc_dist_to_goal(self, x, y): - dx = x - self.end.x - dy = y - self.end.y - return math.hypot(dx, dy) - - def get_random_node(self): - if random.randint(0, 100) > self.goal_sample_rate: - rand_coordinates, n = sobol_quasirand(2, self.sobol_inter_) - - rand_coordinates = self.min_rand + \ - rand_coordinates*(self.max_rand - self.min_rand) - self.sobol_inter_ = n - rnd = self.Node(*rand_coordinates) - - else: # goal point sampling - rnd = self.Node(self.end.x, self.end.y) - return rnd - - def draw_graph(self, rnd=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [sys.exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd.x, rnd.y, "^k") - if self.robot_radius >= 0.0: - self.plot_circle(rnd.x, rnd.y, self.robot_radius, '-r') - for node in self.node_list: - if node.parent: - plt.plot(node.path_x, node.path_y, "-g") - - for (ox, oy, size) in self.obstacle_list: - self.plot_circle(ox, oy, size) - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.end.x, self.end.y, "xr") - plt.axis("equal") - plt.axis([-2, 15, -2, 15]) - plt.grid(True) - plt.pause(0.01) - - @staticmethod - def plot_circle(x, y, size, color="-b"): # pragma: no cover - deg = list(range(0, 360, 5)) - deg.append(0) - xl = [x + size * math.cos(np.deg2rad(d)) for d in deg] - yl = [y + size * math.sin(np.deg2rad(d)) for d in deg] - plt.plot(xl, yl, color) - - @staticmethod - def get_nearest_node_index(node_list, rnd_node): - dlist = [(node.x - rnd_node.x)**2 + (node.y - rnd_node.y)**2 - for node in node_list] - minind = dlist.index(min(dlist)) - - return minind - - @staticmethod - def check_collision(node, obstacle_list, robot_radius): - - if node is None: - return False - - for (ox, oy, size) in obstacle_list: - dx_list = [ox - x for x in node.path_x] - dy_list = [oy - y for y in node.path_y] - d_list = [dx * dx + dy * dy for (dx, dy) in zip(dx_list, dy_list)] - - if min(d_list) <= (size+robot_radius)**2: - return False # collision - - return True # safe - - @staticmethod - def calc_distance_and_angle(from_node, to_node): - dx = to_node.x - from_node.x - dy = to_node.y - from_node.y - d = math.hypot(dx, dy) - theta = math.atan2(dy, dx) - return d, theta - - -def main(gx=6.0, gy=10.0): - print("start " + __file__) - - # ====Search Path with RRTSobol==== - obstacle_list = [(5, 5, 1), (3, 6, 2), (3, 8, 2), (3, 10, 2), (7, 5, 2), - (9, 5, 2), (8, 10, 1)] # [x, y, radius] - # Set Initial parameters - rrt = RRTSobol( - start=[0, 0], - goal=[gx, gy], - rand_area=[-2, 15], - obstacle_list=obstacle_list, - robot_radius=0.8) - path = rrt.planning(animation=show_animation) - - if path is None: - print("Cannot find path") - else: - print("found path!!") - - # Draw final path - if show_animation: - rrt.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.01) # Need for Mac - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRT/sobol/__init__.py b/PathPlanning/RRT/sobol/__init__.py deleted file mode 100644 index c95ac8983b5..00000000000 --- a/PathPlanning/RRT/sobol/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .sobol import i4_sobol as sobol_quasirand diff --git a/PathPlanning/RRT/sobol/sobol.py b/PathPlanning/RRT/sobol/sobol.py deleted file mode 100644 index 520d686a1d3..00000000000 --- a/PathPlanning/RRT/sobol/sobol.py +++ /dev/null @@ -1,911 +0,0 @@ -""" - Licensing: - This code is distributed under the MIT license. - - Authors: - Original FORTRAN77 version of i4_sobol by Bennett Fox. - MATLAB version by John Burkardt. - PYTHON version by Corrado Chisari - - Original Python version of is_prime by Corrado Chisari - - Original MATLAB versions of other functions by John Burkardt. - PYTHON versions by Corrado Chisari - - Original code is available at - https://people.sc.fsu.edu/~jburkardt/py_src/sobol/sobol.html - - Note: the i4 prefix means that the function takes a numeric argument or - returns a number which is interpreted inside the function as a 4 - byte integer - Note: the r4 prefix means that the function takes a numeric argument or - returns a number which is interpreted inside the function as a 4 - byte float -""" -import math -import sys -import numpy as np - -atmost = None -dim_max = None -dim_num_save = None -initialized = None -lastq = None -log_max = None -maxcol = None -poly = None -recipd = None -seed_save = None -v = None - - -def i4_bit_hi1(n): - """ - I4_BIT_HI1 returns the position of the high 1 bit base 2 in an I4. - - Discussion: - - An I4 is an integer ( kind = 4 ) value. - - Example: - - N Binary Hi 1 - ---- -------- ---- - 0 0 0 - 1 1 1 - 2 10 2 - 3 11 2 - 4 100 3 - 5 101 3 - 6 110 3 - 7 111 3 - 8 1000 4 - 9 1001 4 - 10 1010 4 - 11 1011 4 - 12 1100 4 - 13 1101 4 - 14 1110 4 - 15 1111 4 - 16 10000 5 - 17 10001 5 - 1023 1111111111 10 - 1024 10000000000 11 - 1025 10000000001 11 - - Licensing: - - This code is distributed under the GNU LGPL license. - - Modified: - - 26 October 2014 - - Author: - - John Burkardt - - Parameters: - - Input, integer N, the integer to be measured. - N should be nonnegative. If N is nonpositive, the function - will always be 0. - - Output, integer BIT, the position of the highest bit. - - """ - i = n - bit = 0 - - while True: - - if i <= 0: - break - - bit = bit + 1 - i = i // 2 - - return bit - - -def i4_bit_lo0(n): - """ - I4_BIT_LO0 returns the position of the low 0 bit base 2 in an I4. - - Discussion: - - An I4 is an integer ( kind = 4 ) value. - - Example: - - N Binary Lo 0 - ---- -------- ---- - 0 0 1 - 1 1 2 - 2 10 1 - 3 11 3 - 4 100 1 - 5 101 2 - 6 110 1 - 7 111 4 - 8 1000 1 - 9 1001 2 - 10 1010 1 - 11 1011 3 - 12 1100 1 - 13 1101 2 - 14 1110 1 - 15 1111 5 - 16 10000 1 - 17 10001 2 - 1023 1111111111 11 - 1024 10000000000 1 - 1025 10000000001 2 - - Licensing: - - This code is distributed under the GNU LGPL license. - - Modified: - - 08 February 2018 - - Author: - - John Burkardt - - Parameters: - - Input, integer N, the integer to be measured. - N should be nonnegative. - - Output, integer BIT, the position of the low 1 bit. - - """ - bit = 0 - i = n - - while True: - - bit = bit + 1 - i2 = i // 2 - - if i == 2 * i2: - break - - i = i2 - - return bit - - -def i4_sobol_generate(m, n, skip): - """ - - - I4_SOBOL_GENERATE generates a Sobol dataset. - - Licensing: - - This code is distributed under the MIT license. - - Modified: - - 22 February 2011 - - Author: - - Original MATLAB version by John Burkardt. - PYTHON version by Corrado Chisari - - Parameters: - - Input, integer M, the spatial dimension. - - Input, integer N, the number of points to generate. - - Input, integer SKIP, the number of initial points to skip. - - Output, real R(M,N), the points. - - """ - r = np.zeros((m, n)) - for j in range(1, n + 1): - seed = skip + j - 2 - [r[0:m, j - 1], seed] = i4_sobol(m, seed) - return r - - -def i4_sobol(dim_num, seed): - """ - - - I4_SOBOL generates a new quasirandom Sobol vector with each call. - - Discussion: - - The routine adapts the ideas of Antonov and Saleev. - - Licensing: - - This code is distributed under the MIT license. - - Modified: - - 22 February 2011 - - Author: - - Original FORTRAN77 version by Bennett Fox. - MATLAB version by John Burkardt. - PYTHON version by Corrado Chisari - - Reference: - - Antonov, Saleev, - USSR Computational Mathematics and Mathematical Physics, - olume 19, 19, pages 252 - 256. - - Paul Bratley, Bennett Fox, - Algorithm 659: - Implementing Sobol's Quasirandom Sequence Generator, - ACM Transactions on Mathematical Software, - Volume 14, Number 1, pages 88-100, 1988. - - Bennett Fox, - Algorithm 647: - Implementation and Relative Efficiency of Quasirandom - Sequence Generators, - ACM Transactions on Mathematical Software, - Volume 12, Number 4, pages 362-376, 1986. - - Ilya Sobol, - USSR Computational Mathematics and Mathematical Physics, - Volume 16, pages 236-242, 1977. - - Ilya Sobol, Levitan, - The Production of Points Uniformly Distributed in a Multidimensional - Cube (in Russian), - Preprint IPM Akad. Nauk SSSR, - Number 40, Moscow 1976. - - Parameters: - - Input, integer DIM_NUM, the number of spatial dimensions. - DIM_NUM must satisfy 1 <= DIM_NUM <= 40. - - Input/output, integer SEED, the "seed" for the sequence. - This is essentially the index in the sequence of the quasirandom - value to be generated. On output, SEED has been set to the - appropriate next value, usually simply SEED+1. - If SEED is less than 0 on input, it is treated as though it were 0. - An input value of 0 requests the first (0-th) element of the sequence. - - Output, real QUASI(DIM_NUM), the next quasirandom vector. - - """ - - global atmost - global dim_max - global dim_num_save - global initialized - global lastq - global log_max - global maxcol - global poly - global recipd - global seed_save - global v - - if not initialized or dim_num != dim_num_save: - initialized = 1 - dim_max = 40 - dim_num_save = -1 - log_max = 30 - seed_save = -1 - # - # Initialize (part of) V. - # - v = np.zeros((dim_max, log_max)) - v[0:40, 0] = np.transpose([ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ]) - - v[2:40, 1] = np.transpose([ - 1, 3, 1, 3, 1, 3, 3, 1, 3, 1, 3, 1, 3, 1, 1, 3, 1, 3, 1, 3, 1, 3, - 3, 1, 3, 1, 3, 1, 3, 1, 1, 3, 1, 3, 1, 3, 1, 3 - ]) - - v[3:40, 2] = np.transpose([ - 7, 5, 1, 3, 3, 7, 5, 5, 7, 7, 1, 3, 3, 7, 5, 1, 1, 5, 3, 3, 1, 7, - 5, 1, 3, 3, 7, 5, 1, 1, 5, 7, 7, 5, 1, 3, 3 - ]) - - v[5:40, 3] = np.transpose([ - 1, 7, 9, 13, 11, 1, 3, 7, 9, 5, 13, 13, 11, 3, 15, 5, 3, 15, 7, 9, - 13, 9, 1, 11, 7, 5, 15, 1, 15, 11, 5, 3, 1, 7, 9 - ]) - - v[7:40, 4] = np.transpose([ - 9, 3, 27, 15, 29, 21, 23, 19, 11, 25, 7, 13, 17, 1, 25, 29, 3, 31, - 11, 5, 23, 27, 19, 21, 5, 1, 17, 13, 7, 15, 9, 31, 9 - ]) - - v[13:40, 5] = np.transpose([ - 37, 33, 7, 5, 11, 39, 63, 27, 17, 15, 23, 29, 3, 21, 13, 31, 25, 9, - 49, 33, 19, 29, 11, 19, 27, 15, 25 - ]) - - v[19:40, 6] = np.transpose([ - 13, 33, 115, 41, 79, 17, 29, 119, 75, 73, 105, 7, 59, 65, 21, 3, - 113, 61, 89, 45, 107 - ]) - - v[37:40, 7] = np.transpose([7, 23, 39]) - # - # Set POLY. - # - poly = [ - 1, 3, 7, 11, 13, 19, 25, 37, 59, 47, 61, 55, 41, 67, 97, 91, 109, - 103, 115, 131, 193, 137, 145, 143, 241, 157, 185, 167, 229, 171, - 213, 191, 253, 203, 211, 239, 247, 285, 369, 299 - ] - - atmost = 2**log_max - 1 - # - # Find the number of bits in ATMOST. - # - maxcol = i4_bit_hi1(atmost) - # - # Initialize row 1 of V. - # - v[0, 0:maxcol] = 1 - - # Things to do only if the dimension changed. - - if dim_num != dim_num_save: - # - # Check parameters. - # - if (dim_num < 1 or dim_max < dim_num): - print('I4_SOBOL - Fatal error!') - print(' The spatial dimension DIM_NUM should satisfy:') - print(f' 1 <= DIM_NUM <= {dim_max:d}') - print(f' But this input value is DIM_NUM = {dim_num:d}') - return None - - dim_num_save = dim_num - # - # Initialize the remaining rows of V. - # - for i in range(2, dim_num + 1): - # - # The bits of the integer POLY(I) gives the form of polynomial - # I. - # - # Find the degree of polynomial I from binary encoding. - # - j = poly[i - 1] - m = 0 - while True: - j = math.floor(j / 2.) - if (j <= 0): - break - m = m + 1 - # - # Expand this bit pattern to separate components of the logical - # array INCLUD. - # - j = poly[i - 1] - includ = np.zeros(m) - for k in range(m, 0, -1): - j2 = math.floor(j / 2.) - includ[k - 1] = (j != 2 * j2) - j = j2 - # - # Calculate the remaining elements of row I as explained - # in Bratley and Fox, section 2. - # - for j in range(m + 1, maxcol + 1): - newv = v[i - 1, j - m - 1] - l_var = 1 - for k in range(1, m + 1): - l_var = 2 * l_var - if (includ[k - 1]): - newv = np.bitwise_xor( - int(newv), int(l_var * v[i - 1, j - k - 1])) - v[i - 1, j - 1] = newv -# -# Multiply columns of V by appropriate power of 2. -# - l_var = 1 - for j in range(maxcol - 1, 0, -1): - l_var = 2 * l_var - v[0:dim_num, j - 1] = v[0:dim_num, j - 1] * l_var -# -# RECIPD is 1/(common denominator of the elements in V). -# - recipd = 1.0 / (2 * l_var) - lastq = np.zeros(dim_num) - - seed = int(math.floor(seed)) - - if (seed < 0): - seed = 0 - - if (seed == 0): - l_var = 1 - lastq = np.zeros(dim_num) - - elif (seed == seed_save + 1): - # - # Find the position of the right-hand zero in SEED. - # - l_var = i4_bit_lo0(seed) - - elif seed <= seed_save: - - seed_save = 0 - lastq = np.zeros(dim_num) - - for seed_temp in range(int(seed_save), int(seed)): - l_var = i4_bit_lo0(seed_temp) - for i in range(1, dim_num + 1): - lastq[i - 1] = np.bitwise_xor( - int(lastq[i - 1]), int(v[i - 1, l_var - 1])) - - l_var = i4_bit_lo0(seed) - - elif (seed_save + 1 < seed): - - for seed_temp in range(int(seed_save + 1), int(seed)): - l_var = i4_bit_lo0(seed_temp) - for i in range(1, dim_num + 1): - lastq[i - 1] = np.bitwise_xor( - int(lastq[i - 1]), int(v[i - 1, l_var - 1])) - - l_var = i4_bit_lo0(seed) -# -# Check that the user is not calling too many times! -# - if maxcol < l_var: - print('I4_SOBOL - Fatal error!') - print(' Too many calls!') - print(f' MAXCOL = {maxcol:d}\n') - print(f' L = {l_var:d}\n') - return None - - -# -# Calculate the new components of QUASI. -# - quasi = np.zeros(dim_num) - for i in range(1, dim_num + 1): - quasi[i - 1] = lastq[i - 1] * recipd - lastq[i - 1] = np.bitwise_xor( - int(lastq[i - 1]), int(v[i - 1, l_var - 1])) - - seed_save = seed - seed = seed + 1 - - return [quasi, seed] - - -def i4_uniform_ab(a, b, seed): - """ - - - I4_UNIFORM_AB returns a scaled pseudorandom I4. - - Discussion: - - The pseudorandom number will be scaled to be uniformly distributed - between A and B. - - Licensing: - - This code is distributed under the GNU LGPL license. - - Modified: - - 05 April 2013 - - Author: - - John Burkardt - - Reference: - - Paul Bratley, Bennett Fox, Linus Schrage, - A Guide to Simulation, - Second Edition, - Springer, 1987, - ISBN: 0387964673, - LC: QA76.9.C65.B73. - - Bennett Fox, - Algorithm 647: - Implementation and Relative Efficiency of Quasirandom - Sequence Generators, - ACM Transactions on Mathematical Software, - Volume 12, Number 4, December 1986, pages 362-376. - - Pierre L'Ecuyer, - Random Number Generation, - in Handbook of Simulation, - edited by Jerry Banks, - Wiley, 1998, - ISBN: 0471134031, - LC: T57.62.H37. - - Peter Lewis, Allen Goodman, James Miller, - A Pseudo-Random Number Generator for the System/360, - IBM Systems Journal, - Volume 8, Number 2, 1969, pages 136-143. - - Parameters: - - Input, integer A, B, the minimum and maximum acceptable values. - - Input, integer SEED, a seed for the random number generator. - - Output, integer C, the randomly chosen integer. - - Output, integer SEED, the updated seed. - - """ - - i4_huge = 2147483647 - - seed = int(seed) - - seed = (seed % i4_huge) - - if seed < 0: - seed = seed + i4_huge - - if seed == 0: - print('') - print('I4_UNIFORM_AB - Fatal error!') - print(' Input SEED = 0!') - sys.exit('I4_UNIFORM_AB - Fatal error!') - - k = (seed // 127773) - - seed = 167 * (seed - k * 127773) - k * 2836 - - if seed < 0: - seed = seed + i4_huge - - r = seed * 4.656612875E-10 - # - # Scale R to lie between A-0.5 and B+0.5. - # - a = round(a) - b = round(b) - - r = (1.0 - r) * (min(a, b) - 0.5) \ - + r * (max(a, b) + 0.5) - # - # Use rounding to convert R to an integer between A and B. - # - value = round(r) - - value = max(value, min(a, b)) - value = min(value, max(a, b)) - value = int(value) - - return value, seed - - -def prime_ge(n): - """ - - - PRIME_GE returns the smallest prime greater than or equal to N. - - Example: - - N PRIME_GE - - -10 2 - 1 2 - 2 2 - 3 3 - 4 5 - 5 5 - 6 7 - 7 7 - 8 11 - 9 11 - 10 11 - - Licensing: - - This code is distributed under the MIT license. - - Modified: - - 22 February 2011 - - Author: - - Original MATLAB version by John Burkardt. - PYTHON version by Corrado Chisari - - Parameters: - - Input, integer N, the number to be bounded. - - Output, integer P, the smallest prime number that is greater - than or equal to N. - - """ - p = max(math.ceil(n), 2) - while not isprime(p): - p = p + 1 - - return p - - -def isprime(n): - """ - - - IS_PRIME returns True if N is a prime number, False otherwise - - Licensing: - - This code is distributed under the MIT license. - - Modified: - - 22 February 2011 - - Author: - - Corrado Chisari - - Parameters: - - Input, integer N, the number to be checked. - - Output, boolean value, True or False - - """ - if n != int(n) or n < 1: - return False - p = 2 - while p < n: - if n % p == 0: - return False - p += 1 - - return True - - -def r4_uniform_01(seed): - """ - - - R4_UNIFORM_01 returns a unit pseudorandom R4. - - Discussion: - - This routine implements the recursion - - seed = 167 * seed mod ( 2^31 - 1 ) - r = seed / ( 2^31 - 1 ) - - The integer arithmetic never requires more than 32 bits, - including a sign bit. - - If the initial seed is 12345, then the first three computations are - - Input Output R4_UNIFORM_01 - SEED SEED - - 12345 207482415 0.096616 - 207482415 1790989824 0.833995 - 1790989824 2035175616 0.947702 - - Licensing: - - This code is distributed under the GNU LGPL license. - - Modified: - - 04 April 2013 - - Author: - - John Burkardt - - Reference: - - Paul Bratley, Bennett Fox, Linus Schrage, - A Guide to Simulation, - Second Edition, - Springer, 1987, - ISBN: 0387964673, - LC: QA76.9.C65.B73. - - Bennett Fox, - Algorithm 647: - Implementation and Relative Efficiency of Quasirandom - Sequence Generators, - ACM Transactions on Mathematical Software, - Volume 12, Number 4, December 1986, pages 362-376. - - Pierre L'Ecuyer, - Random Number Generation, - in Handbook of Simulation, - edited by Jerry Banks, - Wiley, 1998, - ISBN: 0471134031, - LC: T57.62.H37. - - Peter Lewis, Allen Goodman, James Miller, - A Pseudo-Random Number Generator for the System/360, - IBM Systems Journal, - Volume 8, Number 2, 1969, pages 136-143. - - Parameters: - - Input, integer SEED, the integer "seed" used to generate - the output random number. SEED should not be 0. - - Output, real R, a random value between 0 and 1. - - Output, integer SEED, the updated seed. This would - normally be used as the input seed on the next call. - - """ - - i4_huge = 2147483647 - - if (seed == 0): - print('') - print('R4_UNIFORM_01 - Fatal error!') - print(' Input SEED = 0!') - sys.exit('R4_UNIFORM_01 - Fatal error!') - - seed = (seed % i4_huge) - - if seed < 0: - seed = seed + i4_huge - - k = (seed // 127773) - - seed = 167 * (seed - k * 127773) - k * 2836 - - if seed < 0: - seed = seed + i4_huge - - r = seed * 4.656612875E-10 - - return r, seed - - -def r8mat_write(filename, m, n, a): - """ - - - R8MAT_WRITE writes an R8MAT to a file. - - Licensing: - - This code is distributed under the GNU LGPL license. - - Modified: - - 12 October 2014 - - Author: - - John Burkardt - - Parameters: - - Input, string FILENAME, the name of the output file. - - Input, integer M, the number of rows in A. - - Input, integer N, the number of columns in A. - - Input, real A(M,N), the matrix. - """ - - with open(filename, 'w') as output: - for i in range(0, m): - for j in range(0, n): - s = f' {a[i, j]:g}' - output.write(s) - output.write('\n') - - -def tau_sobol(dim_num): - """ - - - TAU_SOBOL defines favorable starting seeds for Sobol sequences. - - Discussion: - - For spatial dimensions 1 through 13, this routine returns - a "favorable" value TAU by which an appropriate starting point - in the Sobol sequence can be determined. - - These starting points have the form N = 2**K, where - for integration problems, it is desirable that - TAU + DIM_NUM - 1 <= K - while for optimization problems, it is desirable that - TAU < K. - - Licensing: - - This code is distributed under the MIT license. - - Modified: - - 22 February 2011 - - Author: - - Original FORTRAN77 version by Bennett Fox. - MATLAB version by John Burkardt. - PYTHON version by Corrado Chisari - - Reference: - - IA Antonov, VM Saleev, - USSR Computational Mathematics and Mathematical Physics, - Volume 19, 19, pages 252 - 256. - - Paul Bratley, Bennett Fox, - Algorithm 659: - Implementing Sobol's Quasirandom Sequence Generator, - ACM Transactions on Mathematical Software, - Volume 14, Number 1, pages 88-100, 1988. - - Bennett Fox, - Algorithm 647: - Implementation and Relative Efficiency of Quasirandom - Sequence Generators, - ACM Transactions on Mathematical Software, - Volume 12, Number 4, pages 362-376, 1986. - - Stephen Joe, Frances Kuo - Remark on Algorithm 659: - Implementing Sobol's Quasirandom Sequence Generator, - ACM Transactions on Mathematical Software, - Volume 29, Number 1, pages 49-57, March 2003. - - Ilya Sobol, - USSR Computational Mathematics and Mathematical Physics, - Volume 16, pages 236-242, 1977. - - Ilya Sobol, YL Levitan, - The Production of Points Uniformly Distributed in a Multidimensional - Cube (in Russian), - Preprint IPM Akad. Nauk SSSR, - Number 40, Moscow 1976. - - Parameters: - - Input, integer DIM_NUM, the spatial dimension. Only values - of 1 through 13 will result in useful responses. - - Output, integer TAU, the value TAU. - - """ - dim_max = 13 - - tau_table = [0, 0, 1, 3, 5, 8, 11, 15, 19, 23, 27, 31, 35] - - if 1 <= dim_num <= dim_max: - tau = tau_table[dim_num] - else: - tau = -1 - - return tau diff --git a/PathPlanning/RRTDubins/__init__.py b/PathPlanning/RRTDubins/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/RRTDubins/rrt_dubins.py b/PathPlanning/RRTDubins/rrt_dubins.py deleted file mode 100644 index f938419f359..00000000000 --- a/PathPlanning/RRTDubins/rrt_dubins.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -Path planning Sample Code with RRT with Dubins path - -author: AtsushiSakai(@Atsushi_twi) - -""" -import copy -import math -import random -import numpy as np -import matplotlib.pyplot as plt -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) # root dir -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from RRT.rrt import RRT -from DubinsPath import dubins_path_planner -from utils.plot import plot_arrow - -show_animation = True - - -class RRTDubins(RRT): - """ - Class for RRT planning with Dubins path - """ - - class Node(RRT.Node): - """ - RRT Node - """ - - def __init__(self, x, y, yaw): - super().__init__(x, y) - self.cost = 0 - self.yaw = yaw - self.path_yaw = [] - - def __init__(self, start, goal, obstacle_list, rand_area, - goal_sample_rate=10, - max_iter=200, - robot_radius=0.0 - ): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacleList:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - robot_radius: robot body modeled as circle with given radius - - """ - self.start = self.Node(start[0], start[1], start[2]) - self.end = self.Node(goal[0], goal[1], goal[2]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.obstacle_list = obstacle_list - - self.curvature = 1.0 # for dubins path - self.goal_yaw_th = np.deg2rad(1.0) - self.goal_xy_th = 0.5 - self.robot_radius = robot_radius - - def planning(self, animation=True, search_until_max_iter=True): - """ - execute planning - - animation: flag for animation on or off - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - print("Iter:", i, ", number of nodes:", len(self.node_list)) - rnd = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd) - new_node = self.steer(self.node_list[nearest_ind], rnd) - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - self.node_list.append(new_node) - - if animation and i % 5 == 0: - self.plot_start_goal_arrow() - self.draw_graph(rnd) - - if (not search_until_max_iter) and new_node: # check reaching the goal - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - - print("reached max iteration") - - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - else: - print("Cannot find path") - - return None - - def draw_graph(self, rnd=None): # pragma: no cover - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd.x, rnd.y, "^k") - for node in self.node_list: - if node.parent: - plt.plot(node.path_x, node.path_y, "-g") - - for (ox, oy, size) in self.obstacle_list: - plt.plot(ox, oy, "ok", ms=30 * size) - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.end.x, self.end.y, "xr") - plt.axis([-2, 15, -2, 15]) - plt.grid(True) - self.plot_start_goal_arrow() - plt.pause(0.01) - - def plot_start_goal_arrow(self): # pragma: no cover - plot_arrow(self.start.x, self.start.y, self.start.yaw) - plot_arrow(self.end.x, self.end.y, self.end.yaw) - - def steer(self, from_node, to_node): - - px, py, pyaw, mode, course_lengths = \ - dubins_path_planner.plan_dubins_path( - from_node.x, from_node.y, from_node.yaw, - to_node.x, to_node.y, to_node.yaw, self.curvature) - - if len(px) <= 1: # cannot find a dubins path - return None - - new_node = copy.deepcopy(from_node) - new_node.x = px[-1] - new_node.y = py[-1] - new_node.yaw = pyaw[-1] - - new_node.path_x = px - new_node.path_y = py - new_node.path_yaw = pyaw - new_node.cost += sum([abs(c) for c in course_lengths]) - new_node.parent = from_node - - return new_node - - def calc_new_cost(self, from_node, to_node): - - _, _, _, _, course_length = dubins_path_planner.plan_dubins_path( - from_node.x, from_node.y, from_node.yaw, - to_node.x, to_node.y, to_node.yaw, self.curvature) - - return from_node.cost + course_length - - def get_random_node(self): - - if random.randint(0, 100) > self.goal_sample_rate: - rnd = self.Node(random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand), - random.uniform(-math.pi, math.pi) - ) - else: # goal point sampling - rnd = self.Node(self.end.x, self.end.y, self.end.yaw) - - return rnd - - def search_best_goal_node(self): - - goal_indexes = [] - for (i, node) in enumerate(self.node_list): - if self.calc_dist_to_goal(node.x, node.y) <= self.goal_xy_th: - goal_indexes.append(i) - - # angle check - final_goal_indexes = [] - for i in goal_indexes: - if abs(self.node_list[i].yaw - self.end.yaw) <= self.goal_yaw_th: - final_goal_indexes.append(i) - - if not final_goal_indexes: - return None - - min_cost = min([self.node_list[i].cost for i in final_goal_indexes]) - for i in final_goal_indexes: - if self.node_list[i].cost == min_cost: - return i - - return None - - def generate_final_course(self, goal_index): - print("final") - path = [[self.end.x, self.end.y]] - node = self.node_list[goal_index] - while node.parent: - for (ix, iy) in zip(reversed(node.path_x), reversed(node.path_y)): - path.append([ix, iy]) - node = node.parent - path.append([self.start.x, self.start.y]) - return path - - -def main(): - - print("Start " + __file__) - # ====Search Path with RRT==== - obstacleList = [ - (5, 5, 1), - (3, 6, 2), - (3, 8, 2), - (3, 10, 2), - (7, 5, 2), - (9, 5, 2) - ] # [x,y,size(radius)] - - # Set Initial parameters - start = [0.0, 0.0, np.deg2rad(0.0)] - goal = [10.0, 10.0, np.deg2rad(0.0)] - - rrt_dubins = RRTDubins(start, goal, obstacleList, [-2.0, 15.0]) - path = rrt_dubins.planning(animation=show_animation) - - # Draw final path - if show_animation: # pragma: no cover - rrt_dubins.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.001) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRTStar/__init__.py b/PathPlanning/RRTStar/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/RRTStar/rrt_star.py b/PathPlanning/RRTStar/rrt_star.py deleted file mode 100644 index dcb1a066eb3..00000000000 --- a/PathPlanning/RRTStar/rrt_star.py +++ /dev/null @@ -1,289 +0,0 @@ -""" - -Path planning Sample Code with RRT* - -author: Atsushi Sakai(@Atsushi_twi) - -""" - -import math -import sys -import matplotlib.pyplot as plt -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from RRT.rrt import RRT - -show_animation = True - - -class RRTStar(RRT): - """ - Class for RRT Star planning - """ - - class Node(RRT.Node): - def __init__(self, x, y): - super().__init__(x, y) - self.cost = 0.0 - - def __init__(self, - start, - goal, - obstacle_list, - rand_area, - expand_dis=30.0, - path_resolution=1.0, - goal_sample_rate=20, - max_iter=300, - connect_circle_dist=50.0, - search_until_max_iter=False, - robot_radius=0.0): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacleList:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - - """ - super().__init__(start, goal, obstacle_list, rand_area, expand_dis, - path_resolution, goal_sample_rate, max_iter, - robot_radius=robot_radius) - self.connect_circle_dist = connect_circle_dist - self.goal_node = self.Node(goal[0], goal[1]) - self.search_until_max_iter = search_until_max_iter - self.node_list = [] - - def planning(self, animation=True): - """ - rrt star path planning - - animation: flag for animation on or off . - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - print("Iter:", i, ", number of nodes:", len(self.node_list)) - rnd = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd) - new_node = self.steer(self.node_list[nearest_ind], rnd, - self.expand_dis) - near_node = self.node_list[nearest_ind] - new_node.cost = near_node.cost + \ - math.hypot(new_node.x-near_node.x, - new_node.y-near_node.y) - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - near_inds = self.find_near_nodes(new_node) - node_with_updated_parent = self.choose_parent( - new_node, near_inds) - if node_with_updated_parent: - self.rewire(node_with_updated_parent, near_inds) - self.node_list.append(node_with_updated_parent) - else: - self.node_list.append(new_node) - - if animation: - self.draw_graph(rnd) - - if ((not self.search_until_max_iter) - and new_node): # if reaches goal - last_index = self.search_best_goal_node() - if last_index is not None: - return self.generate_final_course(last_index) - - print("reached max iteration") - - last_index = self.search_best_goal_node() - if last_index is not None: - return self.generate_final_course(last_index) - - return None - - def choose_parent(self, new_node, near_inds): - """ - Computes the cheapest point to new_node contained in the list - near_inds and set such a node as the parent of new_node. - Arguments: - -------- - new_node, Node - randomly generated node with a path from its neared point - There are not coalitions between this node and th tree. - near_inds: list - Indices of indices of the nodes what are near to new_node - - Returns. - ------ - Node, a copy of new_node - """ - if not near_inds: - return None - - # search nearest cost in near_inds - costs = [] - for i in near_inds: - near_node = self.node_list[i] - t_node = self.steer(near_node, new_node) - if t_node and self.check_collision( - t_node, self.obstacle_list, self.robot_radius): - costs.append(self.calc_new_cost(near_node, new_node)) - else: - costs.append(float("inf")) # the cost of collision node - min_cost = min(costs) - - if min_cost == float("inf"): - print("There is no good path.(min_cost is inf)") - return None - - min_ind = near_inds[costs.index(min_cost)] - new_node = self.steer(self.node_list[min_ind], new_node) - new_node.cost = min_cost - - return new_node - - def search_best_goal_node(self): - dist_to_goal_list = [ - self.calc_dist_to_goal(n.x, n.y) for n in self.node_list - ] - goal_inds = [ - dist_to_goal_list.index(i) for i in dist_to_goal_list - if i <= self.expand_dis - ] - - safe_goal_inds = [] - for goal_ind in goal_inds: - t_node = self.steer(self.node_list[goal_ind], self.goal_node) - if self.check_collision( - t_node, self.obstacle_list, self.robot_radius): - safe_goal_inds.append(goal_ind) - - if not safe_goal_inds: - return None - - safe_goal_costs = [self.node_list[i].cost + - self.calc_dist_to_goal(self.node_list[i].x, self.node_list[i].y) - for i in safe_goal_inds] - - min_cost = min(safe_goal_costs) - for i, cost in zip(safe_goal_inds, safe_goal_costs): - if cost == min_cost: - return i - - return None - - def find_near_nodes(self, new_node): - """ - 1) defines a ball centered on new_node - 2) Returns all nodes of the three that are inside this ball - Arguments: - --------- - new_node: Node - new randomly generated node, without collisions between - its nearest node - Returns: - ------- - list - List with the indices of the nodes inside the ball of - radius r - """ - nnode = len(self.node_list) + 1 - r = self.connect_circle_dist * math.sqrt(math.log(nnode) / nnode) - # if expand_dist exists, search vertices in a range no more than - # expand_dist - if hasattr(self, 'expand_dis'): - r = min(r, self.expand_dis) - dist_list = [(node.x - new_node.x)**2 + (node.y - new_node.y)**2 - for node in self.node_list] - near_inds = [dist_list.index(i) for i in dist_list if i <= r**2] - return near_inds - - def rewire(self, new_node, near_inds): - """ - For each node in near_inds, this will check if it is cheaper to - arrive to them from new_node. - In such a case, this will re-assign the parent of the nodes in - near_inds to new_node. - Parameters: - ---------- - new_node, Node - Node randomly added which can be joined to the tree - - near_inds, list of uints - A list of indices of the self.new_node which contains - nodes within a circle of a given radius. - Remark: parent is designated in choose_parent. - - """ - for i in near_inds: - near_node = self.node_list[i] - edge_node = self.steer(new_node, near_node) - if not edge_node: - continue - edge_node.cost = self.calc_new_cost(new_node, near_node) - - no_collision = self.check_collision( - edge_node, self.obstacle_list, self.robot_radius) - improved_cost = near_node.cost > edge_node.cost - - if no_collision and improved_cost: - for node in self.node_list: - if node.parent == self.node_list[i]: - node.parent = edge_node - self.node_list[i] = edge_node - self.propagate_cost_to_leaves(self.node_list[i]) - - def calc_new_cost(self, from_node, to_node): - d, _ = self.calc_distance_and_angle(from_node, to_node) - return from_node.cost + d - - def propagate_cost_to_leaves(self, parent_node): - - for node in self.node_list: - if node.parent == parent_node: - node.cost = self.calc_new_cost(parent_node, node) - self.propagate_cost_to_leaves(node) - - -def main(): - print("Start " + __file__) - - # ====Search Path with RRT==== - obstacle_list = [ - (5, 5, 1), - (3, 6, 2), - (3, 8, 2), - (3, 10, 2), - (7, 5, 2), - (9, 5, 2), - (8, 10, 1), - (6, 12, 1), - ] # [x,y,size(radius)] - - # Set Initial parameters - rrt_star = RRTStar( - start=[0, 0], - goal=[6, 10], - rand_area=[-2, 15], - obstacle_list=obstacle_list, - expand_dis=1, - robot_radius=0.8) - path = rrt_star.planning(animation=show_animation) - - if path is None: - print("Cannot find path") - else: - print("found path!!") - - # Draw final path - if show_animation: - rrt_star.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], 'r--') - plt.grid(True) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRTStarDubins/rrt_star_dubins.py b/PathPlanning/RRTStarDubins/rrt_star_dubins.py deleted file mode 100644 index 7c52879b7c4..00000000000 --- a/PathPlanning/RRTStarDubins/rrt_star_dubins.py +++ /dev/null @@ -1,246 +0,0 @@ -""" -Path planning Sample Code with RRT and Dubins path - -author: AtsushiSakai(@Atsushi_twi) - -""" -import copy -import math -import random -import matplotlib.pyplot as plt -import numpy as np -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) # root dir -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from DubinsPath import dubins_path_planner -from RRTStar.rrt_star import RRTStar -from utils.plot import plot_arrow - -show_animation = True - - -class RRTStarDubins(RRTStar): - """ - Class for RRT star planning with Dubins path - """ - - class Node(RRTStar.Node): - """ - RRT Node - """ - - def __init__(self, x, y, yaw): - super().__init__(x, y) - self.yaw = yaw - self.path_yaw = [] - - def __init__(self, start, goal, obstacle_list, rand_area, - goal_sample_rate=10, - max_iter=200, - connect_circle_dist=50.0, - robot_radius=0.0, - ): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacleList:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - robot_radius: robot body modeled as circle with given radius - - """ - self.start = self.Node(start[0], start[1], start[2]) - self.end = self.Node(goal[0], goal[1], goal[2]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.goal_sample_rate = goal_sample_rate - self.max_iter = max_iter - self.obstacle_list = obstacle_list - self.connect_circle_dist = connect_circle_dist - - self.curvature = 1.0 # for dubins path - self.goal_yaw_th = np.deg2rad(1.0) - self.goal_xy_th = 0.5 - self.robot_radius = robot_radius - - def planning(self, animation=True, search_until_max_iter=True): - """ - RRT Star planning - - animation: flag for animation on or off - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - print("Iter:", i, ", number of nodes:", len(self.node_list)) - rnd = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd) - new_node = self.steer(self.node_list[nearest_ind], rnd) - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - near_indexes = self.find_near_nodes(new_node) - new_node = self.choose_parent(new_node, near_indexes) - if new_node: - self.node_list.append(new_node) - self.rewire(new_node, near_indexes) - - if animation and i % 5 == 0: - self.plot_start_goal_arrow() - self.draw_graph(rnd) - - if (not search_until_max_iter) and new_node: # check reaching the goal - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - - print("reached max iteration") - - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - else: - print("Cannot find path") - - return None - - def draw_graph(self, rnd=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd.x, rnd.y, "^k") - for node in self.node_list: - if node.parent: - plt.plot(node.path_x, node.path_y, "-g") - - for (ox, oy, size) in self.obstacle_list: - plt.plot(ox, oy, "ok", ms=30 * size) - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.end.x, self.end.y, "xr") - plt.axis([-2, 15, -2, 15]) - plt.grid(True) - self.plot_start_goal_arrow() - plt.pause(0.01) - - def plot_start_goal_arrow(self): - plot_arrow(self.start.x, self.start.y, self.start.yaw) - plot_arrow(self.end.x, self.end.y, self.end.yaw) - - def steer(self, from_node, to_node): - - px, py, pyaw, mode, course_lengths = \ - dubins_path_planner.plan_dubins_path( - from_node.x, from_node.y, from_node.yaw, - to_node.x, to_node.y, to_node.yaw, self.curvature) - - if len(px) <= 1: # cannot find a dubins path - return None - - new_node = copy.deepcopy(from_node) - new_node.x = px[-1] - new_node.y = py[-1] - new_node.yaw = pyaw[-1] - - new_node.path_x = px - new_node.path_y = py - new_node.path_yaw = pyaw - new_node.cost += sum([abs(c) for c in course_lengths]) - new_node.parent = from_node - - return new_node - - def calc_new_cost(self, from_node, to_node): - - _, _, _, _, course_lengths = dubins_path_planner.plan_dubins_path( - from_node.x, from_node.y, from_node.yaw, - to_node.x, to_node.y, to_node.yaw, self.curvature) - - cost = sum([abs(c) for c in course_lengths]) - - return from_node.cost + cost - - def get_random_node(self): - - if random.randint(0, 100) > self.goal_sample_rate: - rnd = self.Node(random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand), - random.uniform(-math.pi, math.pi) - ) - else: # goal point sampling - rnd = self.Node(self.end.x, self.end.y, self.end.yaw) - - return rnd - - def search_best_goal_node(self): - - goal_indexes = [] - for (i, node) in enumerate(self.node_list): - if self.calc_dist_to_goal(node.x, node.y) <= self.goal_xy_th: - goal_indexes.append(i) - - # angle check - final_goal_indexes = [] - for i in goal_indexes: - if abs(self.node_list[i].yaw - self.end.yaw) <= self.goal_yaw_th: - final_goal_indexes.append(i) - - if not final_goal_indexes: - return None - - min_cost = min([self.node_list[i].cost for i in final_goal_indexes]) - for i in final_goal_indexes: - if self.node_list[i].cost == min_cost: - return i - - return None - - def generate_final_course(self, goal_index): - print("final") - path = [[self.end.x, self.end.y]] - node = self.node_list[goal_index] - while node.parent: - for (ix, iy) in zip(reversed(node.path_x), reversed(node.path_y)): - path.append([ix, iy]) - node = node.parent - path.append([self.start.x, self.start.y]) - return path - - -def main(): - print("Start rrt star with dubins planning") - - # ====Search Path with RRT==== - obstacleList = [ - (5, 5, 1), - (3, 6, 2), - (3, 8, 2), - (3, 10, 2), - (7, 5, 2), - (9, 5, 2) - ] # [x,y,size(radius)] - - # Set Initial parameters - start = [0.0, 0.0, np.deg2rad(0.0)] - goal = [10.0, 10.0, np.deg2rad(0.0)] - - rrtstar_dubins = RRTStarDubins(start, goal, rand_area=[-2.0, 15.0], obstacle_list=obstacleList) - path = rrtstar_dubins.planning(animation=show_animation) - - # Draw final path - if show_animation: # pragma: no cover - rrtstar_dubins.draw_graph() - plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r') - plt.grid(True) - plt.pause(0.001) - - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/RRTStarReedsShepp/rrt_star_reeds_shepp.py b/PathPlanning/RRTStarReedsShepp/rrt_star_reeds_shepp.py deleted file mode 100644 index c4c3e7c8a8f..00000000000 --- a/PathPlanning/RRTStarReedsShepp/rrt_star_reeds_shepp.py +++ /dev/null @@ -1,265 +0,0 @@ -""" - -Path planning Sample Code with RRT with Reeds-Shepp path - -author: AtsushiSakai(@Atsushi_twi) - -""" -import copy -import math -import random -import sys -import pathlib -import matplotlib.pyplot as plt -import numpy as np -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from ReedsSheppPath import reeds_shepp_path_planning -from RRTStar.rrt_star import RRTStar - -show_animation = True - - -class RRTStarReedsShepp(RRTStar): - """ - Class for RRT star planning with Reeds Shepp path - """ - - class Node(RRTStar.Node): - """ - RRT Node - """ - - def __init__(self, x, y, yaw): - super().__init__(x, y) - self.yaw = yaw - self.path_yaw = [] - - def __init__(self, start, goal, obstacle_list, rand_area, - max_iter=200, step_size=0.2, - connect_circle_dist=50.0, - robot_radius=0.0 - ): - """ - Setting Parameter - - start:Start Position [x,y] - goal:Goal Position [x,y] - obstacleList:obstacle Positions [[x,y,size],...] - randArea:Random Sampling Area [min,max] - robot_radius: robot body modeled as circle with given radius - - """ - self.start = self.Node(start[0], start[1], start[2]) - self.end = self.Node(goal[0], goal[1], goal[2]) - self.min_rand = rand_area[0] - self.max_rand = rand_area[1] - self.max_iter = max_iter - self.step_size = step_size - self.obstacle_list = obstacle_list - self.connect_circle_dist = connect_circle_dist - self.robot_radius = robot_radius - - self.curvature = 1.0 - self.goal_yaw_th = np.deg2rad(1.0) - self.goal_xy_th = 0.5 - - def set_random_seed(self, seed): - random.seed(seed) - - def planning(self, animation=True, search_until_max_iter=True): - """ - planning - - animation: flag for animation on or off - """ - - self.node_list = [self.start] - for i in range(self.max_iter): - print("Iter:", i, ", number of nodes:", len(self.node_list)) - rnd = self.get_random_node() - nearest_ind = self.get_nearest_node_index(self.node_list, rnd) - new_node = self.steer(self.node_list[nearest_ind], rnd) - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - near_indexes = self.find_near_nodes(new_node) - new_node = self.choose_parent(new_node, near_indexes) - if new_node: - self.node_list.append(new_node) - self.rewire(new_node, near_indexes) - self.try_goal_path(new_node) - - if animation and i % 5 == 0: - self.plot_start_goal_arrow() - self.draw_graph(rnd) - - if (not search_until_max_iter) and new_node: # check reaching the goal - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - - print("reached max iteration") - - last_index = self.search_best_goal_node() - if last_index: - return self.generate_final_course(last_index) - else: - print("Cannot find path") - - return None - - def try_goal_path(self, node): - - goal = self.Node(self.end.x, self.end.y, self.end.yaw) - - new_node = self.steer(node, goal) - if new_node is None: - return - - if self.check_collision( - new_node, self.obstacle_list, self.robot_radius): - self.node_list.append(new_node) - - def draw_graph(self, rnd=None): - plt.clf() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if rnd is not None: - plt.plot(rnd.x, rnd.y, "^k") - for node in self.node_list: - if node.parent: - plt.plot(node.path_x, node.path_y, "-g") - - for (ox, oy, size) in self.obstacle_list: - plt.plot(ox, oy, "ok", ms=30 * size) - - plt.plot(self.start.x, self.start.y, "xr") - plt.plot(self.end.x, self.end.y, "xr") - plt.axis([-2, 15, -2, 15]) - plt.grid(True) - self.plot_start_goal_arrow() - plt.pause(0.01) - - def plot_start_goal_arrow(self): - reeds_shepp_path_planning.plot_arrow( - self.start.x, self.start.y, self.start.yaw) - reeds_shepp_path_planning.plot_arrow( - self.end.x, self.end.y, self.end.yaw) - - def steer(self, from_node, to_node): - - px, py, pyaw, mode, course_lengths = reeds_shepp_path_planning.reeds_shepp_path_planning( - from_node.x, from_node.y, from_node.yaw, to_node.x, - to_node.y, to_node.yaw, self.curvature, self.step_size) - - if not px: - return None - - new_node = copy.deepcopy(from_node) - new_node.x = px[-1] - new_node.y = py[-1] - new_node.yaw = pyaw[-1] - - new_node.path_x = px - new_node.path_y = py - new_node.path_yaw = pyaw - new_node.cost += sum([abs(l) for l in course_lengths]) - new_node.parent = from_node - - return new_node - - def calc_new_cost(self, from_node, to_node): - - _, _, _, _, course_lengths = reeds_shepp_path_planning.reeds_shepp_path_planning( - from_node.x, from_node.y, from_node.yaw, to_node.x, - to_node.y, to_node.yaw, self.curvature, self.step_size) - if not course_lengths: - return float("inf") - - return from_node.cost + sum([abs(l) for l in course_lengths]) - - def get_random_node(self): - - rnd = self.Node(random.uniform(self.min_rand, self.max_rand), - random.uniform(self.min_rand, self.max_rand), - random.uniform(-math.pi, math.pi) - ) - - return rnd - - def search_best_goal_node(self): - - goal_indexes = [] - for (i, node) in enumerate(self.node_list): - if self.calc_dist_to_goal(node.x, node.y) <= self.goal_xy_th: - goal_indexes.append(i) - print("goal_indexes:", len(goal_indexes)) - - # angle check - final_goal_indexes = [] - for i in goal_indexes: - if abs(self.node_list[i].yaw - self.end.yaw) <= self.goal_yaw_th: - final_goal_indexes.append(i) - - print("final_goal_indexes:", len(final_goal_indexes)) - - if not final_goal_indexes: - return None - - min_cost = min([self.node_list[i].cost for i in final_goal_indexes]) - print("min_cost:", min_cost) - for i in final_goal_indexes: - if self.node_list[i].cost == min_cost: - return i - - return None - - def generate_final_course(self, goal_index): - path = [[self.end.x, self.end.y, self.end.yaw]] - node = self.node_list[goal_index] - while node.parent: - for (ix, iy, iyaw) in zip(reversed(node.path_x), reversed(node.path_y), reversed(node.path_yaw)): - path.append([ix, iy, iyaw]) - node = node.parent - path.append([self.start.x, self.start.y, self.start.yaw]) - return path - - -def main(max_iter=100): - print("Start " + __file__) - - # ====Search Path with RRT==== - obstacleList = [ - (5, 5, 1), - (4, 6, 1), - (4, 8, 1), - (4, 10, 1), - (6, 5, 1), - (7, 5, 1), - (8, 6, 1), - (8, 8, 1), - (8, 10, 1) - ] # [x,y,size(radius)] - - # Set Initial parameters - start = [0.0, 0.0, np.deg2rad(0.0)] - goal = [6.0, 7.0, np.deg2rad(90.0)] - - rrt_star_reeds_shepp = RRTStarReedsShepp(start, goal, - obstacleList, - [-2.0, 15.0], max_iter=max_iter) - path = rrt_star_reeds_shepp.planning(animation=show_animation) - - # Draw final path - if path and show_animation: # pragma: no cover - rrt_star_reeds_shepp.draw_graph() - plt.plot([x for (x, y, yaw) in path], [y for (x, y, yaw) in path], '-r') - plt.grid(True) - plt.pause(0.001) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/ReedsSheppPath/reeds_shepp_path_planning.py b/PathPlanning/ReedsSheppPath/reeds_shepp_path_planning.py deleted file mode 100644 index 618d1d99ba0..00000000000 --- a/PathPlanning/ReedsSheppPath/reeds_shepp_path_planning.py +++ /dev/null @@ -1,478 +0,0 @@ -""" - -Reeds Shepp path planner sample code - -author Atsushi Sakai(@Atsushi_twi) -co-author Videh Patel(@videh25) : Added the missing RS paths - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import math - -import matplotlib.pyplot as plt -import numpy as np -from utils.angle import angle_mod - -show_animation = True - - -class Path: - """ - Path data container - """ - - def __init__(self): - # course segment length (negative value is backward segment) - self.lengths = [] - # course segment type char ("S": straight, "L": left, "R": right) - self.ctypes = [] - self.L = 0.0 # Total lengths of the path - self.x = [] # x positions - self.y = [] # y positions - self.yaw = [] # orientations [rad] - self.directions = [] # directions (1:forward, -1:backward) - - -def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"): - if isinstance(x, list): - for (ix, iy, iyaw) in zip(x, y, yaw): - plot_arrow(ix, iy, iyaw) - else: - plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw), fc=fc, - ec=ec, head_width=width, head_length=width) - plt.plot(x, y) - - -def pi_2_pi(x): - return angle_mod(x) - -def mod2pi(x): - # Be consistent with fmod in cplusplus here. - v = np.mod(x, np.copysign(2.0 * math.pi, x)) - if v < -math.pi: - v += 2.0 * math.pi - else: - if v > math.pi: - v -= 2.0 * math.pi - return v - -def set_path(paths, lengths, ctypes, step_size): - path = Path() - path.ctypes = ctypes - path.lengths = lengths - path.L = sum(np.abs(lengths)) - - # check same path exist - for i_path in paths: - type_is_same = (i_path.ctypes == path.ctypes) - length_is_close = (sum(np.abs(i_path.lengths)) - path.L) <= step_size - if type_is_same and length_is_close: - return paths # same path found, so do not insert path - - # check path is long enough - if path.L <= step_size: - return paths # too short, so do not insert path - - paths.append(path) - return paths - - -def polar(x, y): - r = math.hypot(x, y) - theta = math.atan2(y, x) - return r, theta - - -def left_straight_left(x, y, phi): - u, t = polar(x - math.sin(phi), y - 1.0 + math.cos(phi)) - if 0.0 <= t <= math.pi: - v = mod2pi(phi - t) - if 0.0 <= v <= math.pi: - return True, [t, u, v], ['L', 'S', 'L'] - - return False, [], [] - - -def left_straight_right(x, y, phi): - u1, t1 = polar(x + math.sin(phi), y - 1.0 - math.cos(phi)) - u1 = u1 ** 2 - if u1 >= 4.0: - u = math.sqrt(u1 - 4.0) - theta = math.atan2(2.0, u) - t = mod2pi(t1 + theta) - v = mod2pi(t - phi) - - if (t >= 0.0) and (v >= 0.0): - return True, [t, u, v], ['L', 'S', 'R'] - - return False, [], [] - - -def left_x_right_x_left(x, y, phi): - zeta = x - math.sin(phi) - eeta = y - 1 + math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 <= 4.0: - A = math.acos(0.25 * u1) - t = mod2pi(A + theta + math.pi/2) - u = mod2pi(math.pi - 2 * A) - v = mod2pi(phi - t - u) - return True, [t, -u, v], ['L', 'R', 'L'] - - return False, [], [] - - -def left_x_right_left(x, y, phi): - zeta = x - math.sin(phi) - eeta = y - 1 + math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 <= 4.0: - A = math.acos(0.25 * u1) - t = mod2pi(A + theta + math.pi/2) - u = mod2pi(math.pi - 2*A) - v = mod2pi(-phi + t + u) - return True, [t, -u, -v], ['L', 'R', 'L'] - - return False, [], [] - - -def left_right_x_left(x, y, phi): - zeta = x - math.sin(phi) - eeta = y - 1 + math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 <= 4.0: - u = math.acos(1 - u1**2 * 0.125) - A = math.asin(2 * math.sin(u) / u1) - t = mod2pi(-A + theta + math.pi/2) - v = mod2pi(t - u - phi) - return True, [t, u, -v], ['L', 'R', 'L'] - - return False, [], [] - - -def left_right_x_left_right(x, y, phi): - zeta = x + math.sin(phi) - eeta = y - 1 - math.cos(phi) - u1, theta = polar(zeta, eeta) - - # Solutions refering to (2 < u1 <= 4) are considered sub-optimal in paper - # Solutions do not exist for u1 > 4 - if u1 <= 2: - A = math.acos((u1 + 2) * 0.25) - t = mod2pi(theta + A + math.pi/2) - u = mod2pi(A) - v = mod2pi(phi - t + 2*u) - if ((t >= 0) and (u >= 0) and (v >= 0)): - return True, [t, u, -u, -v], ['L', 'R', 'L', 'R'] - - return False, [], [] - - -def left_x_right_left_x_right(x, y, phi): - zeta = x + math.sin(phi) - eeta = y - 1 - math.cos(phi) - u1, theta = polar(zeta, eeta) - u2 = (20 - u1**2) / 16 - - if (0 <= u2 <= 1): - u = math.acos(u2) - A = math.asin(2 * math.sin(u) / u1) - t = mod2pi(theta + A + math.pi/2) - v = mod2pi(t - phi) - if (t >= 0) and (v >= 0): - return True, [t, -u, -u, v], ['L', 'R', 'L', 'R'] - - return False, [], [] - - -def left_x_right90_straight_left(x, y, phi): - zeta = x - math.sin(phi) - eeta = y - 1 + math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 >= 2.0: - u = math.sqrt(u1**2 - 4) - 2 - A = math.atan2(2, math.sqrt(u1**2 - 4)) - t = mod2pi(theta + A + math.pi/2) - v = mod2pi(t - phi + math.pi/2) - if (t >= 0) and (v >= 0): - return True, [t, -math.pi/2, -u, -v], ['L', 'R', 'S', 'L'] - - return False, [], [] - - -def left_straight_right90_x_left(x, y, phi): - zeta = x - math.sin(phi) - eeta = y - 1 + math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 >= 2.0: - u = math.sqrt(u1**2 - 4) - 2 - A = math.atan2(math.sqrt(u1**2 - 4), 2) - t = mod2pi(theta - A + math.pi/2) - v = mod2pi(t - phi - math.pi/2) - if (t >= 0) and (v >= 0): - return True, [t, u, math.pi/2, -v], ['L', 'S', 'R', 'L'] - - return False, [], [] - - -def left_x_right90_straight_right(x, y, phi): - zeta = x + math.sin(phi) - eeta = y - 1 - math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 >= 2.0: - t = mod2pi(theta + math.pi/2) - u = u1 - 2 - v = mod2pi(phi - t - math.pi/2) - if (t >= 0) and (v >= 0): - return True, [t, -math.pi/2, -u, -v], ['L', 'R', 'S', 'R'] - - return False, [], [] - - -def left_straight_left90_x_right(x, y, phi): - zeta = x + math.sin(phi) - eeta = y - 1 - math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 >= 2.0: - t = mod2pi(theta) - u = u1 - 2 - v = mod2pi(phi - t - math.pi/2) - if (t >= 0) and (v >= 0): - return True, [t, u, math.pi/2, -v], ['L', 'S', 'L', 'R'] - - return False, [], [] - - -def left_x_right90_straight_left90_x_right(x, y, phi): - zeta = x + math.sin(phi) - eeta = y - 1 - math.cos(phi) - u1, theta = polar(zeta, eeta) - - if u1 >= 4.0: - u = math.sqrt(u1**2 - 4) - 4 - A = math.atan2(2, math.sqrt(u1**2 - 4)) - t = mod2pi(theta + A + math.pi/2) - v = mod2pi(t - phi) - if (t >= 0) and (v >= 0): - return True, [t, -math.pi/2, -u, -math.pi/2, v], ['L', 'R', 'S', 'L', 'R'] - - return False, [], [] - - -def timeflip(travel_distances): - return [-x for x in travel_distances] - - -def reflect(steering_directions): - def switch_dir(dirn): - if dirn == 'L': - return 'R' - elif dirn == 'R': - return 'L' - else: - return 'S' - return[switch_dir(dirn) for dirn in steering_directions] - - -def generate_path(q0, q1, max_curvature, step_size): - dx = q1[0] - q0[0] - dy = q1[1] - q0[1] - dth = q1[2] - q0[2] - c = math.cos(q0[2]) - s = math.sin(q0[2]) - x = (c * dx + s * dy) * max_curvature - y = (-s * dx + c * dy) * max_curvature - step_size *= max_curvature - - paths = [] - path_functions = [left_straight_left, left_straight_right, # CSC - left_x_right_x_left, left_x_right_left, left_right_x_left, # CCC - left_right_x_left_right, left_x_right_left_x_right, # CCCC - left_x_right90_straight_left, left_x_right90_straight_right, # CCSC - left_straight_right90_x_left, left_straight_left90_x_right, # CSCC - left_x_right90_straight_left90_x_right] # CCSCC - - for path_func in path_functions: - flag, travel_distances, steering_dirns = path_func(x, y, dth) - if flag: - for distance in travel_distances: - if (0.1*sum([abs(d) for d in travel_distances]) < abs(distance) < step_size): - print("Step size too large for Reeds-Shepp paths.") - return [] - paths = set_path(paths, travel_distances, steering_dirns, step_size) - - flag, travel_distances, steering_dirns = path_func(-x, y, -dth) - if flag: - for distance in travel_distances: - if (0.1*sum([abs(d) for d in travel_distances]) < abs(distance) < step_size): - print("Step size too large for Reeds-Shepp paths.") - return [] - travel_distances = timeflip(travel_distances) - paths = set_path(paths, travel_distances, steering_dirns, step_size) - - flag, travel_distances, steering_dirns = path_func(x, -y, -dth) - if flag: - for distance in travel_distances: - if (0.1*sum([abs(d) for d in travel_distances]) < abs(distance) < step_size): - print("Step size too large for Reeds-Shepp paths.") - return [] - steering_dirns = reflect(steering_dirns) - paths = set_path(paths, travel_distances, steering_dirns, step_size) - - flag, travel_distances, steering_dirns = path_func(-x, -y, dth) - if flag: - for distance in travel_distances: - if (0.1*sum([abs(d) for d in travel_distances]) < abs(distance) < step_size): - print("Step size too large for Reeds-Shepp paths.") - return [] - travel_distances = timeflip(travel_distances) - steering_dirns = reflect(steering_dirns) - paths = set_path(paths, travel_distances, steering_dirns, step_size) - - return paths - - -def calc_interpolate_dists_list(lengths, step_size): - interpolate_dists_list = [] - for length in lengths: - d_dist = step_size if length >= 0.0 else -step_size - interp_dists = np.arange(0.0, length, d_dist) - interp_dists = np.append(interp_dists, length) - interpolate_dists_list.append(interp_dists) - - return interpolate_dists_list - - -def generate_local_course(lengths, modes, max_curvature, step_size): - interpolate_dists_list = calc_interpolate_dists_list(lengths, step_size * max_curvature) - - origin_x, origin_y, origin_yaw = 0.0, 0.0, 0.0 - - xs, ys, yaws, directions = [], [], [], [] - for (interp_dists, mode, length) in zip(interpolate_dists_list, modes, - lengths): - - for dist in interp_dists: - x, y, yaw, direction = interpolate(dist, length, mode, - max_curvature, origin_x, - origin_y, origin_yaw) - xs.append(x) - ys.append(y) - yaws.append(yaw) - directions.append(direction) - origin_x = xs[-1] - origin_y = ys[-1] - origin_yaw = yaws[-1] - - return xs, ys, yaws, directions - - -def interpolate(dist, length, mode, max_curvature, origin_x, origin_y, - origin_yaw): - if mode == "S": - x = origin_x + dist / max_curvature * math.cos(origin_yaw) - y = origin_y + dist / max_curvature * math.sin(origin_yaw) - yaw = origin_yaw - else: # curve - ldx = math.sin(dist) / max_curvature - ldy = 0.0 - yaw = None - if mode == "L": # left turn - ldy = (1.0 - math.cos(dist)) / max_curvature - yaw = origin_yaw + dist - elif mode == "R": # right turn - ldy = (1.0 - math.cos(dist)) / -max_curvature - yaw = origin_yaw - dist - gdx = math.cos(-origin_yaw) * ldx + math.sin(-origin_yaw) * ldy - gdy = -math.sin(-origin_yaw) * ldx + math.cos(-origin_yaw) * ldy - x = origin_x + gdx - y = origin_y + gdy - - return x, y, yaw, 1 if length > 0.0 else -1 - - -def calc_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size): - q0 = [sx, sy, syaw] - q1 = [gx, gy, gyaw] - - paths = generate_path(q0, q1, maxc, step_size) - for path in paths: - xs, ys, yaws, directions = generate_local_course(path.lengths, - path.ctypes, maxc, - step_size) - - # convert global coordinate - path.x = [math.cos(-q0[2]) * ix + math.sin(-q0[2]) * iy + q0[0] for - (ix, iy) in zip(xs, ys)] - path.y = [-math.sin(-q0[2]) * ix + math.cos(-q0[2]) * iy + q0[1] for - (ix, iy) in zip(xs, ys)] - path.yaw = [pi_2_pi(yaw + q0[2]) for yaw in yaws] - path.directions = directions - path.lengths = [length / maxc for length in path.lengths] - path.L = path.L / maxc - - return paths - - -def reeds_shepp_path_planning(sx, sy, syaw, gx, gy, gyaw, maxc, step_size=0.2): - paths = calc_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size) - if not paths: - return None, None, None, None, None # could not generate any path - - # search minimum cost path - best_path_index = paths.index(min(paths, key=lambda p: abs(p.L))) - b_path = paths[best_path_index] - - return b_path.x, b_path.y, b_path.yaw, b_path.ctypes, b_path.lengths - - -def main(): - print("Reeds Shepp path planner sample start!!") - - start_x = -1.0 # [m] - start_y = -4.0 # [m] - start_yaw = np.deg2rad(-20.0) # [rad] - - end_x = 5.0 # [m] - end_y = 5.0 # [m] - end_yaw = np.deg2rad(25.0) # [rad] - - curvature = 0.1 - step_size = 0.05 - - xs, ys, yaws, modes, lengths = reeds_shepp_path_planning(start_x, start_y, - start_yaw, end_x, - end_y, end_yaw, - curvature, - step_size) - - if not xs: - assert False, "No path" - - if show_animation: # pragma: no cover - plt.cla() - plt.plot(xs, ys, label="final course " + str(modes)) - print(f"{lengths=}") - - # plotting - plot_arrow(start_x, start_y, start_yaw) - plot_arrow(end_x, end_y, end_yaw) - - plt.legend() - plt.grid(True) - plt.axis("equal") - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/SpiralSpanningTreeCPP/map/test.png b/PathPlanning/SpiralSpanningTreeCPP/map/test.png deleted file mode 100644 index 4abca0bf309..00000000000 Binary files a/PathPlanning/SpiralSpanningTreeCPP/map/test.png and /dev/null differ diff --git a/PathPlanning/SpiralSpanningTreeCPP/map/test_2.png b/PathPlanning/SpiralSpanningTreeCPP/map/test_2.png deleted file mode 100644 index 0d27fa9f958..00000000000 Binary files a/PathPlanning/SpiralSpanningTreeCPP/map/test_2.png and /dev/null differ diff --git a/PathPlanning/SpiralSpanningTreeCPP/map/test_3.png b/PathPlanning/SpiralSpanningTreeCPP/map/test_3.png deleted file mode 100644 index 1a50b87ccff..00000000000 Binary files a/PathPlanning/SpiralSpanningTreeCPP/map/test_3.png and /dev/null differ diff --git a/PathPlanning/SpiralSpanningTreeCPP/spiral_spanning_tree_coverage_path_planner.py b/PathPlanning/SpiralSpanningTreeCPP/spiral_spanning_tree_coverage_path_planner.py deleted file mode 100644 index a8c513e6b16..00000000000 --- a/PathPlanning/SpiralSpanningTreeCPP/spiral_spanning_tree_coverage_path_planner.py +++ /dev/null @@ -1,313 +0,0 @@ -""" -Spiral Spanning Tree Coverage Path Planner - -author: Todd Tang -paper: Spiral-STC: An On-Line Coverage Algorithm of Grid Environments - by a Mobile Robot - Gabriely et.al. -link: https://ieeexplore.ieee.org/abstract/document/1013479 -""" - -import os -import sys -import math - -import numpy as np -import matplotlib.pyplot as plt - -do_animation = True - - -class SpiralSpanningTreeCoveragePlanner: - def __init__(self, occ_map): - self.origin_map_height = occ_map.shape[0] - self.origin_map_width = occ_map.shape[1] - - # original map resolution must be even - if self.origin_map_height % 2 == 1 or self.origin_map_width % 2 == 1: - sys.exit('original map width/height must be even \ - in grayscale .png format') - - self.occ_map = occ_map - self.merged_map_height = self.origin_map_height // 2 - self.merged_map_width = self.origin_map_width // 2 - - self.edge = [] - - def plan(self, start): - """plan - - performing Spiral Spanning Tree Coverage path planning - - :param start: the start node of Spiral Spanning Tree Coverage - """ - - visit_times = np.zeros( - (self.merged_map_height, self.merged_map_width), dtype=int) - visit_times[start[0]][start[1]] = 1 - - # generate route by - # recusively call perform_spanning_tree_coverage() from start node - route = [] - self.perform_spanning_tree_coverage(start, visit_times, route) - - path = [] - # generate path from route - for idx in range(len(route)-1): - dp = abs(route[idx][0] - route[idx+1][0]) + \ - abs(route[idx][1] - route[idx+1][1]) - if dp == 0: - # special handle for round-trip path - path.append(self.get_round_trip_path(route[idx-1], route[idx])) - elif dp == 1: - path.append(self.move(route[idx], route[idx+1])) - elif dp == 2: - # special handle for non-adjacent route nodes - mid_node = self.get_intermediate_node(route[idx], route[idx+1]) - path.append(self.move(route[idx], mid_node)) - path.append(self.move(mid_node, route[idx+1])) - else: - sys.exit('adjacent path node distance larger than 2') - - return self.edge, route, path - - def perform_spanning_tree_coverage(self, current_node, visit_times, route): - """perform_spanning_tree_coverage - - recursive function for function <plan> - - :param current_node: current node - """ - - def is_valid_node(i, j): - is_i_valid_bounded = 0 <= i < self.merged_map_height - is_j_valid_bounded = 0 <= j < self.merged_map_width - if is_i_valid_bounded and is_j_valid_bounded: - # free only when the 4 sub-cells are all free - return bool( - self.occ_map[2*i][2*j] - and self.occ_map[2*i+1][2*j] - and self.occ_map[2*i][2*j+1] - and self.occ_map[2*i+1][2*j+1]) - - return False - - # counter-clockwise neighbor finding order - order = [[1, 0], [0, 1], [-1, 0], [0, -1]] - - found = False - route.append(current_node) - for inc in order: - ni, nj = current_node[0] + inc[0], current_node[1] + inc[1] - if is_valid_node(ni, nj) and visit_times[ni][nj] == 0: - neighbor_node = (ni, nj) - self.edge.append((current_node, neighbor_node)) - found = True - visit_times[ni][nj] += 1 - self.perform_spanning_tree_coverage( - neighbor_node, visit_times, route) - - # backtrace route from node with neighbors all visited - # to first node with unvisited neighbor - if not found: - has_node_with_unvisited_ngb = False - for node in reversed(route): - # drop nodes that have been visited twice - if visit_times[node[0]][node[1]] == 2: - continue - - visit_times[node[0]][node[1]] += 1 - route.append(node) - - for inc in order: - ni, nj = node[0] + inc[0], node[1] + inc[1] - if is_valid_node(ni, nj) and visit_times[ni][nj] == 0: - has_node_with_unvisited_ngb = True - break - - if has_node_with_unvisited_ngb: - break - - return route - - def move(self, p, q): - direction = self.get_vector_direction(p, q) - # move east - if direction == 'E': - p = self.get_sub_node(p, 'SE') - q = self.get_sub_node(q, 'SW') - # move west - elif direction == 'W': - p = self.get_sub_node(p, 'NW') - q = self.get_sub_node(q, 'NE') - # move south - elif direction == 'S': - p = self.get_sub_node(p, 'SW') - q = self.get_sub_node(q, 'NW') - # move north - elif direction == 'N': - p = self.get_sub_node(p, 'NE') - q = self.get_sub_node(q, 'SE') - else: - sys.exit('move direction error...') - return [p, q] - - def get_round_trip_path(self, last, pivot): - direction = self.get_vector_direction(last, pivot) - if direction == 'E': - return [self.get_sub_node(pivot, 'SE'), - self.get_sub_node(pivot, 'NE')] - elif direction == 'S': - return [self.get_sub_node(pivot, 'SW'), - self.get_sub_node(pivot, 'SE')] - elif direction == 'W': - return [self.get_sub_node(pivot, 'NW'), - self.get_sub_node(pivot, 'SW')] - elif direction == 'N': - return [self.get_sub_node(pivot, 'NE'), - self.get_sub_node(pivot, 'NW')] - else: - sys.exit('get_round_trip_path: last->pivot direction error.') - - def get_vector_direction(self, p, q): - # east - if p[0] == q[0] and p[1] < q[1]: - return 'E' - # west - elif p[0] == q[0] and p[1] > q[1]: - return 'W' - # south - elif p[0] < q[0] and p[1] == q[1]: - return 'S' - # north - elif p[0] > q[0] and p[1] == q[1]: - return 'N' - else: - sys.exit('get_vector_direction: Only E/W/S/N direction supported.') - - def get_sub_node(self, node, direction): - if direction == 'SE': - return [2*node[0]+1, 2*node[1]+1] - elif direction == 'SW': - return [2*node[0]+1, 2*node[1]] - elif direction == 'NE': - return [2*node[0], 2*node[1]+1] - elif direction == 'NW': - return [2*node[0], 2*node[1]] - else: - sys.exit('get_sub_node: sub-node direction error.') - - def get_interpolated_path(self, p, q): - # direction p->q: southwest / northeast - if (p[0] < q[0]) ^ (p[1] < q[1]): - ipx = [p[0], p[0], q[0]] - ipy = [p[1], q[1], q[1]] - # direction p->q: southeast / northwest - else: - ipx = [p[0], q[0], q[0]] - ipy = [p[1], p[1], q[1]] - return ipx, ipy - - def get_intermediate_node(self, p, q): - p_ngb, q_ngb = set(), set() - - for m, n in self.edge: - if m == p: - p_ngb.add(n) - if n == p: - p_ngb.add(m) - if m == q: - q_ngb.add(n) - if n == q: - q_ngb.add(m) - - itsc = p_ngb.intersection(q_ngb) - if len(itsc) == 0: - sys.exit('get_intermediate_node: \ - no intermediate node between', p, q) - elif len(itsc) == 1: - return list(itsc)[0] - else: - sys.exit('get_intermediate_node: \ - more than 1 intermediate node between', p, q) - - def visualize_path(self, edge, path, start): - def coord_transform(p): - return [2*p[1] + 0.5, 2*p[0] + 0.5] - - if do_animation: - last = path[0][0] - trajectory = [[last[1]], [last[0]]] - for p, q in path: - distance = math.hypot(p[0]-last[0], p[1]-last[1]) - if distance <= 1.0: - trajectory[0].append(p[1]) - trajectory[1].append(p[0]) - else: - ipx, ipy = self.get_interpolated_path(last, p) - trajectory[0].extend(ipy) - trajectory[1].extend(ipx) - - last = q - - trajectory[0].append(last[1]) - trajectory[1].append(last[0]) - - for idx, state in enumerate(np.transpose(trajectory)): - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - # draw spanning tree - plt.imshow(self.occ_map, 'gray') - for p, q in edge: - p = coord_transform(p) - q = coord_transform(q) - plt.plot([p[0], q[0]], [p[1], q[1]], '-oc') - sx, sy = coord_transform(start) - plt.plot([sx], [sy], 'pr', markersize=10) - - # draw move path - plt.plot(trajectory[0][:idx+1], trajectory[1][:idx+1], '-k') - plt.plot(state[0], state[1], 'or') - plt.axis('equal') - plt.grid(True) - plt.pause(0.01) - - else: - # draw spanning tree - plt.imshow(self.occ_map, 'gray') - for p, q in edge: - p = coord_transform(p) - q = coord_transform(q) - plt.plot([p[0], q[0]], [p[1], q[1]], '-oc') - sx, sy = coord_transform(start) - plt.plot([sx], [sy], 'pr', markersize=10) - - # draw move path - last = path[0][0] - for p, q in path: - distance = math.hypot(p[0]-last[0], p[1]-last[1]) - if distance == 1.0: - plt.plot([last[1], p[1]], [last[0], p[0]], '-k') - else: - ipx, ipy = self.get_interpolated_path(last, p) - plt.plot(ipy, ipx, '-k') - plt.arrow(p[1], p[0], q[1]-p[1], q[0]-p[0], head_width=0.2) - last = q - - plt.show() - - -def main(): - dir_path = os.path.dirname(os.path.realpath(__file__)) - img = plt.imread(os.path.join(dir_path, 'map', 'test_2.png')) - STC_planner = SpiralSpanningTreeCoveragePlanner(img) - start = (10, 0) - edge, route, path = STC_planner.plan(start) - STC_planner.visualize_path(edge, path, start) - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/StateLatticePlanner/__init__.py b/PathPlanning/StateLatticePlanner/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/StateLatticePlanner/lookup_table.csv b/PathPlanning/StateLatticePlanner/lookup_table.csv deleted file mode 100644 index 2c48a11a18b..00000000000 --- a/PathPlanning/StateLatticePlanner/lookup_table.csv +++ /dev/null @@ -1,82 +0,0 @@ -x,y,yaw,s,km,kf -1.0,0.0,0.0,1.0,0.0,0.0 -9.975352133559392,0.0482183513545736,0.5660837104214496,10.00000000000002,0.0015736624607596847,0.31729782170754367 -15.021899857204536,0.023109001221800096,0.541061424167431,15.128443053611093,0.0006480950273134919,0.20847475849103875 -20.062147834064536,0.0406648159648112,0.5374967866814861,20.205553097986094,0.000452860235044122,0.15502921850050788 -24.924468605496358,-0.04047324014767662,0.5146575311501209,25.16775431470035,6.940620839146646e-05,0.12259452810198132 -9.971782095506931,1.9821448683146543,0.5206511572266477,10.287478424823748,0.05861430948618236,0.07036494964262185 -15.00170010872385,2.0003864283110473,0.5236741185892617,15.245993376540827,0.02657730439557895,0.09933479864250763 -19.991716537639487,1.9940629519465154,0.5226444441451559,20.277923997037238,0.015108540596275507,0.09478988637993524 -24.946447973869596,2.0815930190993206,0.5306354765686239,25.20115925294013,0.010036251429787917,0.08505936469481987 -10.033694822745312,3.9724800521928056,0.5349578864544497,11.087694168363686,0.10279429366023954,-0.12501011715795404 -15.010712586144749,4.0046776414868095,0.5234972445048012,15.729582155835587,0.05010930398580602,-0.0008557723200034717 -19.9175798257299,4.053680042954521,0.5265397234296523,20.52466275843717,0.029584390559990882,0.035276591227371874 -24.98769016158626,3.991699950598091,0.5229000018897194,25.543297770996556,0.018800715817231053,0.04750751098144048 -10.018665105170687,6.004814533505462,0.5183921334245007,12.249438857228967,0.13207408248643182,-0.2742892277307502 -14.988626131330372,5.991226410357179,0.5248160422552801,16.53593823576699,0.06924423592936522,-0.08634227857486092 -20.014420271646646,6.006767110727591,0.5233060851224174,21.23271362632659,0.041402041787912916,-0.01770377839603589 -24.998338724667267,5.997352722087869,0.5235621854299422,26.009046544833613,0.027285850882345728,0.011507045054418165 -10.040118020822444,8.017131894913126,0.5076867575242261,13.8061261785273,0.14561700178565884,-0.3527538468214878 -14.96397914886416,7.974972375534203,0.5303378183744862,17.667338175004062,0.08318912494381935,-0.15372672981944802 -20.045725182938817,8.023486945646207,0.5201839069343577,22.126364299043573,0.05173969669894265,-0.06557547083017647 -25.004687466358227,8.00036398460779,0.5234938146870878,26.740089158520917,0.034867425244601645,-0.02199309906456302 -10.065138949829214,10.03244363616002,0.49375882493214895,15.701940360254637,0.14847998727328912,-0.39355037236614626 -15.05373212031198,10.026401491912143,0.5111826366036252,19.105461052226858,0.09205576730549936,-0.20458802229704312 -19.965550451103926,9.977668905006206,0.5278605653376056,23.14082140870299,0.06010674632014157,-0.10340577652521214 -25.04062496016141,9.956781577401756,0.5252395961316738,27.641194908523495,0.04115083532669924,-0.05054407239730677 -9.980172344087242,11.981944953180841,0.5354924711458446,17.764377273124804,0.14616069587267325,-0.40115138946106776 -15.031707905116134,12.011530784459552,0.5157261778129998,20.745000892047745,0.0970285785481706,-0.2379719980195133 -20.05384921212195,12.02621662711961,0.5153884987125119,24.513013940487117,0.06601543941341544,-0.13666530932375262 -25.04326204059146,12.019946808479768,0.5198699857547844,28.74306622689766,0.04671545692054678,-0.07827401225777673 -10.005005976167096,13.993516346269931,0.5249997047973469,20.063732124124442,0.14007166951362482,-0.39994549637994103 -15.013469777117386,13.998572375088138,0.5211760827701193,22.591299061495683,0.0989196134377572,-0.25909446951756165 -19.980150236409695,13.98233838451409,0.5278966095736082,25.971685915503254,0.07029833263412807,-0.15993299513197096 -25.009669110020404,14.000751236643762,0.5227555344229664,29.949071374991423,0.05106114063333748,-0.09952052168406796 -9.996712859814979,15.986637217372996,0.5301458018536311,22.47478825250167,0.1329741433122606,-0.38823042580907063 -15.02373126750475,16.00384009060484,0.5182833077580984,24.557463511123004,0.0989491582793761,-0.26836010532851323 -20.023756339113735,16.004847752803656,0.5197401980953318,27.669260302891157,0.07275720314277462,-0.178811991371391 -25.015003771679122,16.002919774604504,0.5219791758565742,31.36524983655211,0.05429827198598215,-0.11766440355003502 -10.078596822781892,18.025309925487992,0.49768408992179225,25.02580432036455,0.1252233187334947,-0.3747545825918585 -15.001968473293188,17.988033772017467,0.5262415135796346,26.67625473617623,0.09746306394892065,-0.27167606206451594 -20.026047062413117,18.00445752595148,0.5193568548054093,29.442158339897595,0.07417227896231118,-0.19015828496001386 -24.984711558393403,17.982744830235063,0.5266809346220684,32.855828700083094,0.05675308229799072,-0.13090299334069386 -9.999999973554228,8.906672256498078e-05,-0.00024912926939091307,9.993250237275609,1.9794429093204823e-06,-0.00016167063578544257 -14.999999988951053,0.00030609885737583985,-9.259737492950393e-05,14.939586274030715,4.066161982234725e-06,-5.3230908443270726e-05 -19.999999963637627,0.0008196433029304879,-0.00010277758318455454,19.985770355960977,6.0902800817987275e-06,-5.581407356116362e-05 -24.999999906323,0.001558015443394581,-0.0001252423879458675,24.925430653319882,7.508303551937611e-06,-5.98269885073166e-05 -9.93201732790474,1.9700581591656137,-0.006606314895513332,10.1625049701131,0.05795554613825405,-0.23594780459354886 -15.017121844754504,2.000131018972639,-0.001958259181754851,15.130494387563031,0.026367577418638183,-0.10529363184139814 -19.962697589600058,2.0003823634817484,0.0021983556339688626,20.055058569558643,0.014972854970102445,-0.0592998512022201 -24.990093248087035,2.0008914594513647,0.0003319006512292333,25.020899019312747,0.009609456446194334,-0.03808543941908436 -9.942924437331126,3.9434423219621073,-0.047789349898090805,10.916318098481405,0.10417074854184473,-0.42509733550937057 -14.976393375378994,3.9987876606083557,0.004653465622298736,15.69826778341493,0.04981535482126709,-0.20027162173052074 -19.954160472557877,4.000101578371634,0.0053292950039418585,20.459066225465484,0.02905576509783228,-0.11479451096219842 -25.06247590490118,3.9997579161047643,-0.00486183691237807,25.40723367563786,0.01874893916371208,-0.07533000027879669 -9.974854017566281,5.998183884411291,0.01394025812352817,12.27808815775426,0.13163310345287574,-0.5111693653344966 -14.99829771854157,5.999020207860274,0.0007330116466723879,16.57520987140955,0.06880393034208837,-0.27508456151767885 -19.98389776689381,5.999506195067484,0.002770060727207646,21.17690590277397,0.04131547230609369,-0.1652252863196287 -25.022089217041394,5.998166050230614,-0.002551136444779001,25.974625009044832,0.02718132258204399,-0.10978755041013998 -9.940106683734614,7.99448983539684,0.03735909486314526,13.864600506318645,0.14554135993596395,-0.5498471044599721 -15.015405965817797,7.996301502316838,-0.004430455799697253,17.779484729664652,0.08234534796805798,-0.3300198333333338 -19.965919061860355,7.998456498324741,0.00732927315681664,22.0665101267907,0.05178054118886435,-0.20507088323830897 -24.97580637673196,7.998036396987909,0.0034859866489540536,26.699711792661176,0.03478260921646504,-0.13959734880932403 -10.003237328881212,9.994037173180942,-0.002542633641336778,15.800576175296408,0.1482242831571022,-0.5606578442626601 -14.95848212484301,9.995827033229693,0.016804720248816185,19.19635868417634,0.09159937492256161,-0.3610497877526804 -20.018365340632464,9.997789133099982,-0.003880405312526758,23.259977677838524,0.05967179836565363,-0.23873172503708404 -25.034844162753302,9.996613275552045,-0.005490232481425661,27.647073656497884,0.04122997694830456,-0.16548182742762063 -10.041413516307436,11.988808245039152,-0.015743247245750158,18.0174427655263,0.14424296158815444,-0.5545987939832356 -15.0710608536628,11.993636485613393,-0.025235844052727163,20.92474299071291,0.0960774359909814,-0.38199459745149106 -20.061838597733104,11.995243972143648,-0.015325438311212025,24.63090823780847,0.06556771814265559,-0.2626353022718591 -24.90813949494271,11.995929681233529,0.01760171116909426,28.6986397040137,0.046810556161518815,-0.1847353186190147 -10.005191819464756,13.97797567430312,0.018961636911005275,20.358534835690133,0.13825179056925302,-0.5307789523538471 -14.978392340358946,13.991362718235834,0.012411272386128935,22.755419658274054,0.0984622955030996,-0.38447788120958937 -20.015767113356507,13.992558840024987,-0.002205036951612893,26.18420998778461,0.06961025144239422,-0.2786494668163888 -25.01318440442437,13.994258255793202,-0.0016239998449329995,30.09124393513656,0.05071043613803722,-0.20387658283659768 -10.038844117562423,15.966797017942504,0.016384527088525225,22.88736140380268,0.13044436631301143,-0.5070826347325453 -14.91898245890566,15.984279670640529,0.03784081306841358,24.796728185207627,0.09830913950807817,-0.38207974071854045 -19.999487117727806,15.99041117221354,0.0034823225688951354,27.881676426972927,0.07220430103629995,-0.2873083396987492 -25.056418472201756,15.995103453935709,-0.011257522827095023,31.50238694595278,0.05406499488342877,-0.21526296035737832 -10.076107447676621,17.952889979512353,0.017798231103724138,25.454959881832874,0.1231232463335769,-0.47600174850950705 -15.032725028551983,17.978015286760307,0.0020752804670070013,27.089888269358894,0.09590219542773218,-0.3801465515462427 -20.03544756240551,17.98685790169768,-0.005300968094156033,29.75070206477736,0.07340450527104486,-0.29182757725382324 -24.960019173190652,17.98909417109214,0.011594018486178026,33.0995680641525,0.05634561447882407,-0.22402297280749597 diff --git a/PathPlanning/StateLatticePlanner/state_lattice_planner.py b/PathPlanning/StateLatticePlanner/state_lattice_planner.py deleted file mode 100644 index 7f8e725e0ac..00000000000 --- a/PathPlanning/StateLatticePlanner/state_lattice_planner.py +++ /dev/null @@ -1,343 +0,0 @@ -""" - -State lattice planner with model predictive trajectory generator - -author: Atsushi Sakai (@Atsushi_twi) - -- plookuptable.csv is generated with this script: -https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathPlanning -/ModelPredictiveTrajectoryGenerator/lookup_table_generator.py - -Ref: - -- State Space Sampling of Feasible Motions for High-Performance Mobile Robot -Navigation in Complex Environments -https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf -&doi=e2256b5b24137f89e473f01df288cb3aa72e56a0 - -""" -import sys -import os -from matplotlib import pyplot as plt -import numpy as np -import math -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -import ModelPredictiveTrajectoryGenerator.trajectory_generator as planner -import ModelPredictiveTrajectoryGenerator.motion_model as motion_model - -TABLE_PATH = os.path.dirname(os.path.abspath(__file__)) + "/lookup_table.csv" - -show_animation = True - - -def search_nearest_one_from_lookup_table(t_x, t_y, t_yaw, lookup_table): - mind = float("inf") - minid = -1 - - for (i, table) in enumerate(lookup_table): - dx = t_x - table[0] - dy = t_y - table[1] - dyaw = t_yaw - table[2] - d = math.sqrt(dx ** 2 + dy ** 2 + dyaw ** 2) - if d <= mind: - minid = i - mind = d - - return lookup_table[minid] - - -def get_lookup_table(table_path): - return np.loadtxt(table_path, delimiter=',', skiprows=1) - - -def generate_path(target_states, k0): - # x, y, yaw, s, km, kf - lookup_table = get_lookup_table(TABLE_PATH) - result = [] - - for state in target_states: - bestp = search_nearest_one_from_lookup_table( - state[0], state[1], state[2], lookup_table) - - target = motion_model.State(x=state[0], y=state[1], yaw=state[2]) - init_p = np.array( - [np.hypot(state[0], state[1]), bestp[4], bestp[5]]).reshape(3, 1) - - x, y, yaw, p = planner.optimize_trajectory(target, k0, init_p) - - if x is not None: - print("find good path") - result.append( - [x[-1], y[-1], yaw[-1], float(p[0, 0]), float(p[1, 0]), float(p[2, 0])]) - - print("finish path generation") - return result - - -def calc_uniform_polar_states(nxy, nh, d, a_min, a_max, p_min, p_max): - """ - - Parameters - ---------- - nxy : - number of position sampling - nh : - number of heading sampleing - d : - distance of terminal state - a_min : - position sampling min angle - a_max : - position sampling max angle - p_min : - heading sampling min angle - p_max : - heading sampling max angle - - Returns - ------- - - """ - angle_samples = [i / (nxy - 1) for i in range(nxy)] - states = sample_states(angle_samples, a_min, a_max, d, p_max, p_min, nh) - - return states - - -def calc_biased_polar_states(goal_angle, ns, nxy, nh, d, a_min, a_max, p_min, p_max): - """ - calc biased state - - :param goal_angle: goal orientation for biased sampling - :param ns: number of biased sampling - :param nxy: number of position sampling - :param nxy: number of position sampling - :param nh: number of heading sampleing - :param d: distance of terminal state - :param a_min: position sampling min angle - :param a_max: position sampling max angle - :param p_min: heading sampling min angle - :param p_max: heading sampling max angle - :return: states list - """ - - asi = [a_min + (a_max - a_min) * i / (ns - 1) for i in range(ns - 1)] - cnav = [math.pi - abs(i - goal_angle) for i in asi] - - cnav_sum = sum(cnav) - cnav_max = max(cnav) - - # normalize - cnav = [(cnav_max - cnav[i]) / (cnav_max * ns - cnav_sum) - for i in range(ns - 1)] - - csumnav = np.cumsum(cnav) - di = [] - li = 0 - for i in range(nxy): - for ii in range(li, ns - 1): - if ii / ns >= i / (nxy - 1): - di.append(csumnav[ii]) - li = ii - 1 - break - - states = sample_states(di, a_min, a_max, d, p_max, p_min, nh) - - return states - - -def calc_lane_states(l_center, l_heading, l_width, v_width, d, nxy): - """ - - calc lane states - - :param l_center: lane lateral position - :param l_heading: lane heading - :param l_width: lane width - :param v_width: vehicle width - :param d: longitudinal position - :param nxy: sampling number - :return: state list - """ - xc = d - yc = l_center - - states = [] - for i in range(nxy): - delta = -0.5 * (l_width - v_width) + \ - (l_width - v_width) * i / (nxy - 1) - xf = xc - delta * math.sin(l_heading) - yf = yc + delta * math.cos(l_heading) - yawf = l_heading - states.append([xf, yf, yawf]) - - return states - - -def sample_states(angle_samples, a_min, a_max, d, p_max, p_min, nh): - states = [] - for i in angle_samples: - a = a_min + (a_max - a_min) * i - - for j in range(nh): - xf = d * math.cos(a) - yf = d * math.sin(a) - if nh == 1: - yawf = (p_max - p_min) / 2 + a - else: - yawf = p_min + (p_max - p_min) * j / (nh - 1) + a - states.append([xf, yf, yawf]) - - return states - - -def uniform_terminal_state_sampling_test1(): - k0 = 0.0 - nxy = 5 - nh = 3 - d = 20 - a_min = - np.deg2rad(45.0) - a_max = np.deg2rad(45.0) - p_min = - np.deg2rad(45.0) - p_max = np.deg2rad(45.0) - states = calc_uniform_polar_states(nxy, nh, d, a_min, a_max, p_min, p_max) - result = generate_path(states, k0) - - for table in result: - xc, yc, yawc = motion_model.generate_trajectory( - table[3], table[4], table[5], k0) - - if show_animation: - plt.plot(xc, yc, "-r") - - if show_animation: - plt.grid(True) - plt.axis("equal") - plt.show() - - print("Done") - - -def uniform_terminal_state_sampling_test2(): - k0 = 0.1 - nxy = 6 - nh = 3 - d = 20 - a_min = - np.deg2rad(-10.0) - a_max = np.deg2rad(45.0) - p_min = - np.deg2rad(20.0) - p_max = np.deg2rad(20.0) - states = calc_uniform_polar_states(nxy, nh, d, a_min, a_max, p_min, p_max) - result = generate_path(states, k0) - - for table in result: - xc, yc, yawc = motion_model.generate_trajectory( - table[3], table[4], table[5], k0) - - if show_animation: - plt.plot(xc, yc, "-r") - - if show_animation: - plt.grid(True) - plt.axis("equal") - plt.show() - - print("Done") - - -def biased_terminal_state_sampling_test1(): - k0 = 0.0 - nxy = 30 - nh = 2 - d = 20 - a_min = np.deg2rad(-45.0) - a_max = np.deg2rad(45.0) - p_min = - np.deg2rad(20.0) - p_max = np.deg2rad(20.0) - ns = 100 - goal_angle = np.deg2rad(0.0) - states = calc_biased_polar_states( - goal_angle, ns, nxy, nh, d, a_min, a_max, p_min, p_max) - result = generate_path(states, k0) - - for table in result: - xc, yc, yawc = motion_model.generate_trajectory( - table[3], table[4], table[5], k0) - if show_animation: - plt.plot(xc, yc, "-r") - - if show_animation: - plt.grid(True) - plt.axis("equal") - plt.show() - - -def biased_terminal_state_sampling_test2(): - k0 = 0.0 - nxy = 30 - nh = 1 - d = 20 - a_min = np.deg2rad(0.0) - a_max = np.deg2rad(45.0) - p_min = - np.deg2rad(20.0) - p_max = np.deg2rad(20.0) - ns = 100 - goal_angle = np.deg2rad(30.0) - states = calc_biased_polar_states( - goal_angle, ns, nxy, nh, d, a_min, a_max, p_min, p_max) - result = generate_path(states, k0) - - for table in result: - xc, yc, yawc = motion_model.generate_trajectory( - table[3], table[4], table[5], k0) - - if show_animation: - plt.plot(xc, yc, "-r") - - if show_animation: - plt.grid(True) - plt.axis("equal") - plt.show() - - -def lane_state_sampling_test1(): - k0 = 0.0 - - l_center = 10.0 - l_heading = np.deg2rad(0.0) - l_width = 3.0 - v_width = 1.0 - d = 10 - nxy = 5 - states = calc_lane_states(l_center, l_heading, l_width, v_width, d, nxy) - result = generate_path(states, k0) - - if show_animation: - plt.close("all") - - for table in result: - x_c, y_c, yaw_c = motion_model.generate_trajectory( - table[3], table[4], table[5], k0) - - if show_animation: - plt.plot(x_c, y_c, "-r") - - if show_animation: - plt.grid(True) - plt.axis("equal") - plt.show() - - -def main(): - planner.show_animation = show_animation - uniform_terminal_state_sampling_test1() - uniform_terminal_state_sampling_test2() - biased_terminal_state_sampling_test1() - biased_terminal_state_sampling_test2() - lane_state_sampling_test1() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/TimeBasedPathPlanning/GridWithDynamicObstacles.py b/PathPlanning/TimeBasedPathPlanning/GridWithDynamicObstacles.py deleted file mode 100644 index 2a47023f8cd..00000000000 --- a/PathPlanning/TimeBasedPathPlanning/GridWithDynamicObstacles.py +++ /dev/null @@ -1,331 +0,0 @@ -""" -This file implements a grid with a 3d reservation matrix with dimensions for x, y, and time. There -is also infrastructure to generate dynamic obstacles that move around the grid. The obstacles' paths -are stored in the reservation matrix on creation. -""" -import numpy as np -import matplotlib.pyplot as plt -from enum import Enum -from dataclasses import dataclass - -@dataclass(order=True) -class Position: - x: int - y: int - - def as_ndarray(self) -> np.ndarray: - return np.array([self.x, self.y]) - - def __add__(self, other): - if isinstance(other, Position): - return Position(self.x + other.x, self.y + other.y) - raise NotImplementedError( - f"Addition not supported for Position and {type(other)}" - ) - - def __sub__(self, other): - if isinstance(other, Position): - return Position(self.x - other.x, self.y - other.y) - raise NotImplementedError( - f"Subtraction not supported for Position and {type(other)}" - ) - - def __hash__(self): - return hash((self.x, self.y)) - -@dataclass -class Interval: - start_time: int - end_time: int - -class ObstacleArrangement(Enum): - # Random obstacle positions and movements - RANDOM = 0 - # Obstacles start in a line in y at center of grid and move side-to-side in x - ARRANGEMENT1 = 1 - -""" -Generates a 2d numpy array with lists for elements. -""" -def empty_2d_array_of_lists(x: int, y: int) -> np.ndarray: - arr = np.empty((x, y), dtype=object) - # assign each element individually - np.full creates references to the same list - arr[:] = [[[] for _ in range(y)] for _ in range(x)] - return arr - -class Grid: - # Set in constructor - grid_size: np.ndarray - reservation_matrix: np.ndarray - obstacle_paths: list[list[Position]] = [] - # Obstacles will never occupy these points. Useful to avoid impossible scenarios - obstacle_avoid_points: list[Position] = [] - - # Number of time steps in the simulation - time_limit: int - - # Logging control - verbose = False - - def __init__( - self, - grid_size: np.ndarray, - num_obstacles: int = 40, - obstacle_avoid_points: list[Position] = [], - obstacle_arrangement: ObstacleArrangement = ObstacleArrangement.RANDOM, - time_limit: int = 100, - ): - self.obstacle_avoid_points = obstacle_avoid_points - self.time_limit = time_limit - self.grid_size = grid_size - self.reservation_matrix = np.zeros((grid_size[0], grid_size[1], self.time_limit)) - - if num_obstacles > self.grid_size[0] * self.grid_size[1]: - raise Exception("Number of obstacles is greater than grid size!") - - if obstacle_arrangement == ObstacleArrangement.RANDOM: - self.obstacle_paths = self.generate_dynamic_obstacles(num_obstacles) - elif obstacle_arrangement == ObstacleArrangement.ARRANGEMENT1: - self.obstacle_paths = self.obstacle_arrangement_1(num_obstacles) - - for i, path in enumerate(self.obstacle_paths): - obs_idx = i + 1 # avoid using 0 - that indicates free space in the grid - for t, position in enumerate(path): - # Reserve old & new position at this time step - if t > 0: - self.reservation_matrix[path[t - 1].x, path[t - 1].y, t] = obs_idx - self.reservation_matrix[position.x, position.y, t] = obs_idx - - """ - Generate dynamic obstacles that move around the grid. Initial positions and movements are random - """ - def generate_dynamic_obstacles(self, obs_count: int) -> list[list[Position]]: - obstacle_paths = [] - for _ in range(0, obs_count): - # Sample until a free starting space is found - initial_position = self.sample_random_position() - while not self.valid_obstacle_position(initial_position, 0): - initial_position = self.sample_random_position() - - positions = [initial_position] - if self.verbose: - print("Obstacle initial position: ", initial_position) - - # Encourage obstacles to mostly stay in place - too much movement leads to chaotic planning scenarios - # that are not fun to watch - weights = [0.05, 0.05, 0.05, 0.05, 0.8] - diffs = [ - Position(0, 1), - Position(0, -1), - Position(1, 0), - Position(-1, 0), - Position(0, 0), - ] - - for t in range(1, self.time_limit - 1): - sampled_indices = np.random.choice( - len(diffs), size=5, replace=False, p=weights - ) - rand_diffs = [diffs[i] for i in sampled_indices] - - valid_position = None - for diff in rand_diffs: - new_position = positions[-1] + diff - - if not self.valid_obstacle_position(new_position, t): - continue - - valid_position = new_position - break - - # Impossible situation for obstacle - stay in place - # -> this can happen if the oaths of other obstacles this one - if valid_position is None: - valid_position = positions[-1] - - positions.append(valid_position) - - obstacle_paths.append(positions) - - return obstacle_paths - - """ - Generate a line of obstacles in y at the center of the grid that move side-to-side in x - Bottom half start moving right, top half start moving left. If `obs_count` is less than the length of - the grid, only the first `obs_count` obstacles will be generated. - """ - def obstacle_arrangement_1(self, obs_count: int) -> list[list[Position]]: - obstacle_paths = [] - half_grid_x = self.grid_size[0] // 2 - half_grid_y = self.grid_size[1] // 2 - - for y_idx in range(0, min(obs_count, self.grid_size[1])): - moving_right = y_idx < half_grid_y - position = Position(half_grid_x, y_idx) - path = [position] - - for t in range(1, self.time_limit - 1): - # sit in place every other time step - if t % 2 == 0: - path.append(position) - continue - - # first check if we should switch direction (at edge of grid) - if (moving_right and position.x == self.grid_size[0] - 1) or ( - not moving_right and position.x == 0 - ): - moving_right = not moving_right - # step in direction - position = Position( - position.x + (1 if moving_right else -1), position.y - ) - path.append(position) - - obstacle_paths.append(path) - - return obstacle_paths - - """ - Check if the given position is valid at time t - - input: - position (Position): (x, y) position - t (int): time step - - output: - bool: True if position/time combination is valid, False otherwise - """ - def valid_position(self, position: Position, t: int) -> bool: - # Check if new position is in grid - if not self.inside_grid_bounds(position): - return False - - # Check if new position is not occupied at time t - return self.reservation_matrix[position.x, position.y, t] == 0 - - """ - Returns True if the given position is valid at time t and is not in the set of obstacle_avoid_points - """ - def valid_obstacle_position(self, position: Position, t: int) -> bool: - return ( - self.valid_position(position, t) - and position not in self.obstacle_avoid_points - ) - - """ - Returns True if the given position is within the grid's boundaries - """ - def inside_grid_bounds(self, position: Position) -> bool: - return ( - position.x >= 0 - and position.x < self.grid_size[0] - and position.y >= 0 - and position.y < self.grid_size[1] - ) - - """ - Sample a random position that is within the grid's boundaries - - output: - Position: (x, y) position - """ - def sample_random_position(self) -> Position: - return Position( - np.random.randint(0, self.grid_size[0]), - np.random.randint(0, self.grid_size[1]), - ) - - """ - Returns a tuple of (x_positions, y_positions) of the obstacles at time t - """ - def get_obstacle_positions_at_time(self, t: int) -> tuple[list[int], list[int]]: - x_positions = [] - y_positions = [] - for obs_path in self.obstacle_paths: - x_positions.append(obs_path[t].x) - y_positions.append(obs_path[t].y) - return (x_positions, y_positions) - - """ - Returns safe intervals for each cell. - """ - def get_safe_intervals(self) -> np.ndarray: - intervals = empty_2d_array_of_lists(self.grid_size[0], self.grid_size[1]) - for x in range(intervals.shape[0]): - for y in range(intervals.shape[1]): - intervals[x, y] = self.get_safe_intervals_at_cell(Position(x, y)) - - return intervals - - """ - Generate the safe intervals for a given cell. The intervals will be in order of start time. - ex: Interval (2, 3) will be before Interval (4, 5) - """ - def get_safe_intervals_at_cell(self, cell: Position) -> list[Interval]: - vals = self.reservation_matrix[cell.x, cell.y, :] - # Find where the array is zero - zero_mask = (vals == 0) - - # Identify transitions between zero and nonzero elements - diff = np.diff(zero_mask.astype(int)) - - # Start indices: where zeros begin (1 after a nonzero) - start_indices = np.where(diff == 1)[0] + 1 - - # End indices: where zeros stop (just before a nonzero) - end_indices = np.where(diff == -1)[0] - - # Handle edge cases if the array starts or ends with zeros - if zero_mask[0]: # If the first element is zero, add index 0 to start_indices - start_indices = np.insert(start_indices, 0, 0) - if zero_mask[-1]: # If the last element is zero, add the last index to end_indices - end_indices = np.append(end_indices, len(vals) - 1) - - # Create pairs of (first zero, last zero) - intervals = [Interval(int(start), int(end)) for start, end in zip(start_indices, end_indices)] - - # Remove intervals where a cell is only free for one time step. Those intervals not provide enough time to - # move into and out of the cell each take 1 time step, and the cell is considered occupied during - # both the time step when it is entering the cell, and the time step when it is leaving the cell. - intervals = [interval for interval in intervals if interval.start_time != interval.end_time] - return intervals - -show_animation = True - - -def main(): - grid = Grid( - np.array([11, 11]), - num_obstacles=10, - obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1, - ) - - if not show_animation: - return - - fig = plt.figure(figsize=(8, 7)) - ax = fig.add_subplot( - autoscale_on=False, - xlim=(0, grid.grid_size[0] - 1), - ylim=(0, grid.grid_size[1] - 1), - ) - ax.set_aspect("equal") - ax.grid() - ax.set_xticks(np.arange(0, 11, 1)) - ax.set_yticks(np.arange(0, 11, 1)) - (obs_points,) = ax.plot([], [], "ro", ms=15) - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - "key_release_event", lambda event: [exit(0) if event.key == "escape" else None] - ) - - for i in range(0, grid.time_limit - 1): - obs_positions = grid.get_obstacle_positions_at_time(i) - obs_points.set_data(obs_positions[0], obs_positions[1]) - plt.pause(0.2) - plt.show() - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/TimeBasedPathPlanning/SafeInterval.py b/PathPlanning/TimeBasedPathPlanning/SafeInterval.py deleted file mode 100644 index 7fea10c67fb..00000000000 --- a/PathPlanning/TimeBasedPathPlanning/SafeInterval.py +++ /dev/null @@ -1,303 +0,0 @@ -""" -Safe interval path planner - This script implements a safe-interval path planner for a 2d grid with dynamic obstacles. It is faster than - SpaceTime A* because it reduces the number of redundant node expansions by pre-computing regions of adjacent - time steps that are safe ("safe intervals") at each position. This allows the algorithm to skip expanding nodes - that are in intervals that have already been visited earlier. - - Reference: https://www.cs.cmu.edu/~maxim/files/sipp_icra11.pdf -""" - -import numpy as np -import matplotlib.pyplot as plt -from PathPlanning.TimeBasedPathPlanning.GridWithDynamicObstacles import ( - Grid, - Interval, - ObstacleArrangement, - Position, - empty_2d_array_of_lists, -) -import heapq -import random -from dataclasses import dataclass -from functools import total_ordering -import time - -@dataclass() -# Note: Total_ordering is used instead of adding `order=True` to the @dataclass decorator because -# this class needs to override the __lt__ and __eq__ methods to ignore parent_index. The Parent -# index and interval member variables are just used to track the path found by the algorithm, -# and has no effect on the quality of a node. -@total_ordering -class Node: - position: Position - time: int - heuristic: int - parent_index: int - interval: Interval - - """ - This is what is used to drive node expansion. The node with the lowest value is expanded next. - This comparison prioritizes the node with the lowest cost-to-come (self.time) + cost-to-go (self.heuristic) - """ - def __lt__(self, other: object): - if not isinstance(other, Node): - return NotImplementedError(f"Cannot compare Node with object of type: {type(other)}") - return (self.time + self.heuristic) < (other.time + other.heuristic) - - """ - Equality only cares about position and time. Heuristic and interval will always be the same for a given - (position, time) pairing, so they are not considered in equality. - """ - def __eq__(self, other: object): - if not isinstance(other, Node): - return NotImplemented - return self.position == other.position and self.time == other.time - -@dataclass -class EntryTimeAndInterval: - entry_time: int - interval: Interval - -class NodePath: - path: list[Node] - positions_at_time: dict[int, Position] = {} - - def __init__(self, path: list[Node]): - self.path = path - for (i, node) in enumerate(path): - if i > 0: - # account for waiting in interval at previous node - prev_node = path[i-1] - for t in range(prev_node.time, node.time): - self.positions_at_time[t] = prev_node.position - - self.positions_at_time[node.time] = node.position - - """ - Get the position of the path at a given time - """ - def get_position(self, time: int) -> Position | None: - return self.positions_at_time.get(time) - - """ - Time stamp of the last node in the path - """ - def goal_reached_time(self) -> int: - return self.path[-1].time - - def __repr__(self): - repr_string = "" - for i, node in enumerate(self.path): - repr_string += f"{i}: {node}\n" - return repr_string - - -class SafeIntervalPathPlanner: - grid: Grid - start: Position - goal: Position - - def __init__(self, grid: Grid, start: Position, goal: Position): - self.grid = grid - self.start = start - self.goal = goal - - # Seed randomness for reproducibility - RANDOM_SEED = 50 - random.seed(RANDOM_SEED) - np.random.seed(RANDOM_SEED) - - """ - Generate a plan given the loaded problem statement. Raises an exception if it fails to find a path. - Arguments: - verbose (bool): set to True to print debug information - """ - def plan(self, verbose: bool = False) -> NodePath: - - safe_intervals = self.grid.get_safe_intervals() - - open_set: list[Node] = [] - first_node_interval = safe_intervals[self.start.x, self.start.y][0] - heapq.heappush( - open_set, Node(self.start, 0, self.calculate_heuristic(self.start), -1, first_node_interval) - ) - - expanded_list: list[Node] = [] - visited_intervals = empty_2d_array_of_lists(self.grid.grid_size[0], self.grid.grid_size[1]) - while open_set: - expanded_node: Node = heapq.heappop(open_set) - if verbose: - print("Expanded node:", expanded_node) - - if expanded_node.time + 1 >= self.grid.time_limit: - if verbose: - print(f"\tSkipping node that is past time limit: {expanded_node}") - continue - - if expanded_node.position == self.goal: - print(f"Found path to goal after {len(expanded_list)} expansions") - path = [] - path_walker: Node = expanded_node - while True: - path.append(path_walker) - if path_walker.parent_index == -1: - break - path_walker = expanded_list[path_walker.parent_index] - - # reverse path so it goes start -> goal - path.reverse() - return NodePath(path) - - expanded_idx = len(expanded_list) - expanded_list.append(expanded_node) - entry_time_and_node = EntryTimeAndInterval(expanded_node.time, expanded_node.interval) - add_entry_to_visited_intervals_array(entry_time_and_node, visited_intervals, expanded_node) - - for child in self.generate_successors(expanded_node, expanded_idx, safe_intervals, visited_intervals): - heapq.heappush(open_set, child) - - raise Exception("No path found") - - """ - Generate list of possible successors of the provided `parent_node` that are worth expanding - """ - def generate_successors( - self, parent_node: Node, parent_node_idx: int, intervals: np.ndarray, visited_intervals: np.ndarray - ) -> list[Node]: - new_nodes = [] - diffs = [ - Position(0, 0), - Position(1, 0), - Position(-1, 0), - Position(0, 1), - Position(0, -1), - ] - for diff in diffs: - new_pos = parent_node.position + diff - if not self.grid.inside_grid_bounds(new_pos): - continue - - current_interval = parent_node.interval - - new_cell_intervals: list[Interval] = intervals[new_pos.x, new_pos.y] - for interval in new_cell_intervals: - # if interval starts after current ends, break - # assumption: intervals are sorted by start time, so all future intervals will hit this condition as well - if interval.start_time > current_interval.end_time: - break - - # if interval ends before current starts, skip - if interval.end_time < current_interval.start_time: - continue - - # if we have already expanded a node in this interval with a <= starting time, skip - better_node_expanded = False - for visited in visited_intervals[new_pos.x, new_pos.y]: - if interval == visited.interval and visited.entry_time <= parent_node.time + 1: - better_node_expanded = True - break - if better_node_expanded: - continue - - # We know there is a node worth expanding. Generate successor at the earliest possible time the - # new interval can be entered - for possible_t in range(max(parent_node.time + 1, interval.start_time), min(current_interval.end_time, interval.end_time)): - if self.grid.valid_position(new_pos, possible_t): - new_nodes.append(Node( - new_pos, - # entry is max of interval start and parent node time + 1 (get there as soon as possible) - max(interval.start_time, parent_node.time + 1), - self.calculate_heuristic(new_pos), - parent_node_idx, - interval, - )) - # break because all t's after this will make nodes with a higher cost, the same heuristic, and are in the same interval - break - - return new_nodes - - """ - Calculate the heuristic for a given position - Manhattan distance to the goal - """ - def calculate_heuristic(self, position) -> int: - diff = self.goal - position - return abs(diff.x) + abs(diff.y) - - -""" -Adds a new entry to the visited intervals array. If the entry is already present, the entry time is updated if the new -entry time is better. Otherwise, the entry is added to `visited_intervals` at the position of `expanded_node`. -""" -def add_entry_to_visited_intervals_array(entry_time_and_interval: EntryTimeAndInterval, visited_intervals: np.ndarray, expanded_node: Node): - # if entry is present, update entry time if better - for existing_entry_and_interval in visited_intervals[expanded_node.position.x, expanded_node.position.y]: - if existing_entry_and_interval.interval == entry_time_and_interval.interval: - existing_entry_and_interval.entry_time = min(existing_entry_and_interval.entry_time, entry_time_and_interval.entry_time) - - # Otherwise, append - visited_intervals[expanded_node.position.x, expanded_node.position.y].append(entry_time_and_interval) - - -show_animation = True -verbose = False - -def main(): - start = Position(1, 18) - goal = Position(19, 19) - grid_side_length = 21 - - start_time = time.time() - - grid = Grid( - np.array([grid_side_length, grid_side_length]), - num_obstacles=250, - obstacle_avoid_points=[start, goal], - obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1, - # obstacle_arrangement=ObstacleArrangement.RANDOM, - ) - - planner = SafeIntervalPathPlanner(grid, start, goal) - path = planner.plan(verbose) - runtime = time.time() - start_time - print(f"Planning took: {runtime:.5f} seconds") - - if verbose: - print(f"Path: {path}") - - if not show_animation: - return - - fig = plt.figure(figsize=(10, 7)) - ax = fig.add_subplot( - autoscale_on=False, - xlim=(0, grid.grid_size[0] - 1), - ylim=(0, grid.grid_size[1] - 1), - ) - ax.set_aspect("equal") - ax.grid() - ax.set_xticks(np.arange(0, grid_side_length, 1)) - ax.set_yticks(np.arange(0, grid_side_length, 1)) - - (start_and_goal,) = ax.plot([], [], "mD", ms=15, label="Start and Goal") - start_and_goal.set_data([start.x, goal.x], [start.y, goal.y]) - (obs_points,) = ax.plot([], [], "ro", ms=15, label="Obstacles") - (path_points,) = ax.plot([], [], "bo", ms=10, label="Path Found") - ax.legend(bbox_to_anchor=(1.05, 1)) - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - "key_release_event", lambda event: [exit(0) if event.key == "escape" else None] - ) - - for i in range(0, path.goal_reached_time() + 1): - obs_positions = grid.get_obstacle_positions_at_time(i) - obs_points.set_data(obs_positions[0], obs_positions[1]) - path_position = path.get_position(i) - path_points.set_data([path_position.x], [path_position.y]) - plt.pause(0.2) - plt.show() - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/TimeBasedPathPlanning/SpaceTimeAStar.py b/PathPlanning/TimeBasedPathPlanning/SpaceTimeAStar.py deleted file mode 100644 index c4e2802d372..00000000000 --- a/PathPlanning/TimeBasedPathPlanning/SpaceTimeAStar.py +++ /dev/null @@ -1,241 +0,0 @@ -""" -Space-time A* Algorithm - This script demonstrates the Space-time A* algorithm for path planning in a grid world with moving obstacles. - This algorithm is different from normal 2D A* in one key way - the cost (often notated as g(n)) is - the number of time steps it took to get to a given node, instead of the number of cells it has - traversed. This ensures the path is time-optimal, while respecting any dynamic obstacles in the environment. - - Reference: https://www.davidsilver.uk/wp-content/uploads/2020/03/coop-path-AIWisdom.pdf -""" - -import numpy as np -import matplotlib.pyplot as plt -from PathPlanning.TimeBasedPathPlanning.GridWithDynamicObstacles import ( - Grid, - ObstacleArrangement, - Position, -) -import heapq -from collections.abc import Generator -import random -from dataclasses import dataclass -from functools import total_ordering -import time - -# Seed randomness for reproducibility -RANDOM_SEED = 50 -random.seed(RANDOM_SEED) -np.random.seed(RANDOM_SEED) - -@dataclass() -# Note: Total_ordering is used instead of adding `order=True` to the @dataclass decorator because -# this class needs to override the __lt__ and __eq__ methods to ignore parent_index. Parent -# index is just used to track the path found by the algorithm, and has no effect on the quality -# of a node. -@total_ordering -class Node: - position: Position - time: int - heuristic: int - parent_index: int - - """ - This is what is used to drive node expansion. The node with the lowest value is expanded next. - This comparison prioritizes the node with the lowest cost-to-come (self.time) + cost-to-go (self.heuristic) - """ - def __lt__(self, other: object): - if not isinstance(other, Node): - return NotImplementedError(f"Cannot compare Node with object of type: {type(other)}") - return (self.time + self.heuristic) < (other.time + other.heuristic) - - """ - Note: cost and heuristic are not included in eq or hash, since they will always be the same - for a given (position, time) pair. Including either cost or heuristic would be redundant. - """ - def __eq__(self, other: object): - if not isinstance(other, Node): - return NotImplementedError(f"Cannot compare Node with object of type: {type(other)}") - return self.position == other.position and self.time == other.time - - def __hash__(self): - return hash((self.position, self.time)) - -class NodePath: - path: list[Node] - positions_at_time: dict[int, Position] = {} - - def __init__(self, path: list[Node]): - self.path = path - for node in path: - self.positions_at_time[node.time] = node.position - - """ - Get the position of the path at a given time - """ - def get_position(self, time: int) -> Position | None: - return self.positions_at_time.get(time) - - """ - Time stamp of the last node in the path - """ - def goal_reached_time(self) -> int: - return self.path[-1].time - - def __repr__(self): - repr_string = "" - for i, node in enumerate(self.path): - repr_string += f"{i}: {node}\n" - return repr_string - - -class SpaceTimeAStar: - grid: Grid - start: Position - goal: Position - # Used to evaluate solutions - expanded_node_count: int = -1 - - def __init__(self, grid: Grid, start: Position, goal: Position): - self.grid = grid - self.start = start - self.goal = goal - - def plan(self, verbose: bool = False) -> NodePath: - open_set: list[Node] = [] - heapq.heappush( - open_set, Node(self.start, 0, self.calculate_heuristic(self.start), -1) - ) - - expanded_list: list[Node] = [] - expanded_set: set[Node] = set() - while open_set: - expanded_node: Node = heapq.heappop(open_set) - if verbose: - print("Expanded node:", expanded_node) - - if expanded_node.time + 1 >= self.grid.time_limit: - if verbose: - print(f"\tSkipping node that is past time limit: {expanded_node}") - continue - - if expanded_node.position == self.goal: - print(f"Found path to goal after {len(expanded_list)} expansions") - path = [] - path_walker: Node = expanded_node - while True: - path.append(path_walker) - if path_walker.parent_index == -1: - break - path_walker = expanded_list[path_walker.parent_index] - - # reverse path so it goes start -> goal - path.reverse() - self.expanded_node_count = len(expanded_set) - return NodePath(path) - - expanded_idx = len(expanded_list) - expanded_list.append(expanded_node) - expanded_set.add(expanded_node) - - for child in self.generate_successors(expanded_node, expanded_idx, verbose, expanded_set): - heapq.heappush(open_set, child) - - raise Exception("No path found") - - """ - Generate possible successors of the provided `parent_node` - """ - def generate_successors( - self, parent_node: Node, parent_node_idx: int, verbose: bool, expanded_set: set[Node] - ) -> Generator[Node, None, None]: - diffs = [ - Position(0, 0), - Position(1, 0), - Position(-1, 0), - Position(0, 1), - Position(0, -1), - ] - for diff in diffs: - new_pos = parent_node.position + diff - new_node = Node( - new_pos, - parent_node.time + 1, - self.calculate_heuristic(new_pos), - parent_node_idx, - ) - - if new_node in expanded_set: - continue - - if self.grid.valid_position(new_pos, parent_node.time + 1): - if verbose: - print("\tNew successor node: ", new_node) - yield new_node - - def calculate_heuristic(self, position) -> int: - diff = self.goal - position - return abs(diff.x) + abs(diff.y) - - -show_animation = True -verbose = False - -def main(): - start = Position(1, 5) - goal = Position(19, 19) - grid_side_length = 21 - - start_time = time.time() - - grid = Grid( - np.array([grid_side_length, grid_side_length]), - num_obstacles=40, - obstacle_avoid_points=[start, goal], - obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1, - ) - - planner = SpaceTimeAStar(grid, start, goal) - path = planner.plan(verbose) - - runtime = time.time() - start_time - print(f"Planning took: {runtime:.5f} seconds") - - if verbose: - print(f"Path: {path}") - - if not show_animation: - return - - fig = plt.figure(figsize=(10, 7)) - ax = fig.add_subplot( - autoscale_on=False, - xlim=(0, grid.grid_size[0] - 1), - ylim=(0, grid.grid_size[1] - 1), - ) - ax.set_aspect("equal") - ax.grid() - ax.set_xticks(np.arange(0, grid_side_length, 1)) - ax.set_yticks(np.arange(0, grid_side_length, 1)) - - (start_and_goal,) = ax.plot([], [], "mD", ms=15, label="Start and Goal") - start_and_goal.set_data([start.x, goal.x], [start.y, goal.y]) - (obs_points,) = ax.plot([], [], "ro", ms=15, label="Obstacles") - (path_points,) = ax.plot([], [], "bo", ms=10, label="Path Found") - ax.legend(bbox_to_anchor=(1.05, 1)) - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - "key_release_event", lambda event: [exit(0) if event.key == "escape" else None] - ) - - for i in range(0, path.goal_reached_time()): - obs_positions = grid.get_obstacle_positions_at_time(i) - obs_points.set_data(obs_positions[0], obs_positions[1]) - path_position = path.get_position(i) - path_points.set_data([path_position.x], [path_position.y]) - plt.pause(0.2) - plt.show() - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/TimeBasedPathPlanning/__init__.py b/PathPlanning/TimeBasedPathPlanning/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/VisibilityRoadMap/__init__.py b/PathPlanning/VisibilityRoadMap/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/VisibilityRoadMap/geometry.py b/PathPlanning/VisibilityRoadMap/geometry.py deleted file mode 100644 index b15cdb8a43a..00000000000 --- a/PathPlanning/VisibilityRoadMap/geometry.py +++ /dev/null @@ -1,44 +0,0 @@ -class Geometry: - - class Point: - def __init__(self, x, y): - self.x = x - self.y = y - - @staticmethod - def is_seg_intersect(p1, q1, p2, q2): - - def on_segment(p, q, r): - if ((q.x <= max(p.x, r.x)) and (q.x >= min(p.x, r.x)) and - (q.y <= max(p.y, r.y)) and (q.y >= min(p.y, r.y))): - return True - return False - - def orientation(p, q, r): - val = (float(q.y - p.y) * (r.x - q.x)) - ( - float(q.x - p.x) * (r.y - q.y)) - if val > 0: - return 1 - if val < 0: - return 2 - return 0 - - # Find the 4 orientations required for - # the general and special cases - o1 = orientation(p1, q1, p2) - o2 = orientation(p1, q1, q2) - o3 = orientation(p2, q2, p1) - o4 = orientation(p2, q2, q1) - - if (o1 != o2) and (o3 != o4): - return True - if (o1 == 0) and on_segment(p1, p2, q1): - return True - if (o2 == 0) and on_segment(p1, q2, q1): - return True - if (o3 == 0) and on_segment(p2, p1, q2): - return True - if (o4 == 0) and on_segment(p2, q1, q2): - return True - - return False diff --git a/PathPlanning/VisibilityRoadMap/visibility_road_map.py b/PathPlanning/VisibilityRoadMap/visibility_road_map.py deleted file mode 100644 index 5f7ffadd16f..00000000000 --- a/PathPlanning/VisibilityRoadMap/visibility_road_map.py +++ /dev/null @@ -1,222 +0,0 @@ -""" - -Visibility Road Map Planner - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import sys -import math -import numpy as np -import matplotlib.pyplot as plt -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from VisibilityRoadMap.geometry import Geometry -from VoronoiRoadMap.dijkstra_search import DijkstraSearch - -show_animation = True - - -class VisibilityRoadMap: - - def __init__(self, expand_distance, do_plot=False): - self.expand_distance = expand_distance - self.do_plot = do_plot - - def planning(self, start_x, start_y, goal_x, goal_y, obstacles): - - nodes = self.generate_visibility_nodes(start_x, start_y, - goal_x, goal_y, obstacles) - - road_map_info = self.generate_road_map_info(nodes, obstacles) - - if self.do_plot: - self.plot_road_map(nodes, road_map_info) - plt.pause(1.0) - - rx, ry = DijkstraSearch(show_animation).search( - start_x, start_y, - goal_x, goal_y, - [node.x for node in nodes], - [node.y for node in nodes], - road_map_info - ) - - return rx, ry - - def generate_visibility_nodes(self, start_x, start_y, goal_x, goal_y, - obstacles): - - # add start and goal as nodes - nodes = [DijkstraSearch.Node(start_x, start_y), - DijkstraSearch.Node(goal_x, goal_y, 0, None)] - - # add vertexes in configuration space as nodes - for obstacle in obstacles: - - cvx_list, cvy_list = self.calc_vertexes_in_configuration_space( - obstacle.x_list, obstacle.y_list) - - for (vx, vy) in zip(cvx_list, cvy_list): - nodes.append(DijkstraSearch.Node(vx, vy)) - - if self.do_plot: - for node in nodes: - plt.plot(node.x, node.y, "xr") - - return nodes - - def calc_vertexes_in_configuration_space(self, x_list, y_list): - x_list = x_list[0:-1] - y_list = y_list[0:-1] - cvx_list, cvy_list = [], [] - - n_data = len(x_list) - - for index in range(n_data): - offset_x, offset_y = self.calc_offset_xy( - x_list[index - 1], y_list[index - 1], - x_list[index], y_list[index], - x_list[(index + 1) % n_data], y_list[(index + 1) % n_data], - ) - cvx_list.append(offset_x) - cvy_list.append(offset_y) - - return cvx_list, cvy_list - - def generate_road_map_info(self, nodes, obstacles): - - road_map_info_list = [] - - for target_node in nodes: - road_map_info = [] - for node_id, node in enumerate(nodes): - if np.hypot(target_node.x - node.x, - target_node.y - node.y) <= 0.1: - continue - - is_valid = True - for obstacle in obstacles: - if not self.is_edge_valid(target_node, node, obstacle): - is_valid = False - break - if is_valid: - road_map_info.append(node_id) - - road_map_info_list.append(road_map_info) - - return road_map_info_list - - @staticmethod - def is_edge_valid(target_node, node, obstacle): - - for i in range(len(obstacle.x_list) - 1): - p1 = Geometry.Point(target_node.x, target_node.y) - p2 = Geometry.Point(node.x, node.y) - p3 = Geometry.Point(obstacle.x_list[i], obstacle.y_list[i]) - p4 = Geometry.Point(obstacle.x_list[i + 1], obstacle.y_list[i + 1]) - - if Geometry.is_seg_intersect(p1, p2, p3, p4): - return False - - return True - - def calc_offset_xy(self, px, py, x, y, nx, ny): - p_vec = math.atan2(y - py, x - px) - n_vec = math.atan2(ny - y, nx - x) - offset_vec = math.atan2(math.sin(p_vec) + math.sin(n_vec), - math.cos(p_vec) + math.cos( - n_vec)) + math.pi / 2.0 - offset_x = x + self.expand_distance * math.cos(offset_vec) - offset_y = y + self.expand_distance * math.sin(offset_vec) - return offset_x, offset_y - - @staticmethod - def plot_road_map(nodes, road_map_info_list): - for i, node in enumerate(nodes): - for index in road_map_info_list[i]: - plt.plot([node.x, nodes[index].x], - [node.y, nodes[index].y], "-b") - - -class ObstaclePolygon: - - def __init__(self, x_list, y_list): - self.x_list = x_list - self.y_list = y_list - - self.close_polygon() - self.make_clockwise() - - def make_clockwise(self): - if not self.is_clockwise(): - self.x_list = list(reversed(self.x_list)) - self.y_list = list(reversed(self.y_list)) - - def is_clockwise(self): - n_data = len(self.x_list) - eval_sum = sum([(self.x_list[i + 1] - self.x_list[i]) * - (self.y_list[i + 1] + self.y_list[i]) - for i in range(n_data - 1)]) - eval_sum += (self.x_list[0] - self.x_list[n_data - 1]) * \ - (self.y_list[0] + self.y_list[n_data - 1]) - return eval_sum >= 0 - - def close_polygon(self): - is_x_same = self.x_list[0] == self.x_list[-1] - is_y_same = self.y_list[0] == self.y_list[-1] - if is_x_same and is_y_same: - return # no need to close - - self.x_list.append(self.x_list[0]) - self.y_list.append(self.y_list[0]) - - def plot(self): - plt.plot(self.x_list, self.y_list, "-k") - - -def main(): - print(__file__ + " start!!") - - # start and goal position - sx, sy = 10.0, 10.0 # [m] - gx, gy = 50.0, 50.0 # [m] - - expand_distance = 5.0 # [m] - - obstacles = [ - ObstaclePolygon( - [20.0, 30.0, 15.0], - [20.0, 20.0, 30.0], - ), - ObstaclePolygon( - [40.0, 45.0, 50.0, 40.0], - [50.0, 40.0, 20.0, 40.0], - ), - ObstaclePolygon( - [20.0, 30.0, 30.0, 20.0], - [40.0, 45.0, 60.0, 50.0], - ) - ] - - if show_animation: # pragma: no cover - plt.plot(sx, sy, "or") - plt.plot(gx, gy, "ob") - for ob in obstacles: - ob.plot() - plt.axis("equal") - plt.pause(1.0) - - rx, ry = VisibilityRoadMap(expand_distance, do_plot=show_animation)\ - .planning(sx, sy, gx, gy, obstacles) - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.1) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/VoronoiRoadMap/__init__.py b/PathPlanning/VoronoiRoadMap/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathPlanning/VoronoiRoadMap/dijkstra_search.py b/PathPlanning/VoronoiRoadMap/dijkstra_search.py deleted file mode 100644 index 503ccc342eb..00000000000 --- a/PathPlanning/VoronoiRoadMap/dijkstra_search.py +++ /dev/null @@ -1,140 +0,0 @@ -""" - -Dijkstra Search library - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import matplotlib.pyplot as plt -import math -import numpy as np - - -class DijkstraSearch: - class Node: - """ - Node class for dijkstra search - """ - - def __init__(self, x, y, cost=None, parent=None, edge_ids=None): - self.x = x - self.y = y - self.cost = cost - self.parent = parent - self.edge_ids = edge_ids - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent) - - def __init__(self, show_animation): - self.show_animation = show_animation - - def search(self, sx, sy, gx, gy, node_x, node_y, edge_ids_list): - """ - Search shortest path - - s_x: start x positions [m] - s_y: start y positions [m] - gx: goal x position [m] - gx: goal x position [m] - node_x: node x position - node_y: node y position - edge_ids_list: edge_list each item includes a list of edge ids - """ - - start_node = self.Node(sx, sy, 0.0, -1) - goal_node = self.Node(gx, gy, 0.0, -1) - current_node = None - - open_set, close_set = dict(), dict() - open_set[self.find_id(node_x, node_y, start_node)] = start_node - - while True: - if self.has_node_in_set(close_set, goal_node): - print("goal is found!") - goal_node.parent = current_node.parent - goal_node.cost = current_node.cost - break - elif not open_set: - print("Cannot find path") - break - - current_id = min(open_set, key=lambda o: open_set[o].cost) - current_node = open_set[current_id] - - # show graph - if self.show_animation and len( - close_set.keys()) % 2 == 0: # pragma: no cover - plt.plot(current_node.x, current_node.y, "xg") - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.pause(0.1) - - # Remove the item from the open set - del open_set[current_id] - # Add it to the closed set - close_set[current_id] = current_node - - # expand search grid based on motion model - for i in range(len(edge_ids_list[current_id])): - n_id = edge_ids_list[current_id][i] - dx = node_x[n_id] - current_node.x - dy = node_y[n_id] - current_node.y - d = math.hypot(dx, dy) - node = self.Node(node_x[n_id], node_y[n_id], - current_node.cost + d, current_id) - - if n_id in close_set: - continue - # Otherwise if it is already in the open set - if n_id in open_set: - if open_set[n_id].cost > node.cost: - open_set[n_id] = node - else: - open_set[n_id] = node - - # generate final course - rx, ry = self.generate_final_path(close_set, goal_node) - - return rx, ry - - @staticmethod - def generate_final_path(close_set, goal_node): - rx, ry = [goal_node.x], [goal_node.y] - parent = goal_node.parent - while parent != -1: - n = close_set[parent] - rx.append(n.x) - ry.append(n.y) - parent = n.parent - rx, ry = rx[::-1], ry[::-1] # reverse it - return rx, ry - - def has_node_in_set(self, target_set, node): - for key in target_set: - if self.is_same_node(target_set[key], node): - return True - return False - - def find_id(self, node_x_list, node_y_list, target_node): - for i, _ in enumerate(node_x_list): - if self.is_same_node_with_xy(node_x_list[i], node_y_list[i], - target_node): - return i - return None - - @staticmethod - def is_same_node_with_xy(node_x, node_y, node_b): - dist = np.hypot(node_x - node_b.x, - node_y - node_b.y) - return dist <= 0.1 - - @staticmethod - def is_same_node(node_a, node_b): - dist = np.hypot(node_a.x - node_b.x, - node_a.y - node_b.y) - return dist <= 0.1 diff --git a/PathPlanning/VoronoiRoadMap/voronoi_road_map.py b/PathPlanning/VoronoiRoadMap/voronoi_road_map.py deleted file mode 100644 index a27e1b69285..00000000000 --- a/PathPlanning/VoronoiRoadMap/voronoi_road_map.py +++ /dev/null @@ -1,186 +0,0 @@ -""" - -Voronoi Road Map Planner - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math -import numpy as np -import matplotlib.pyplot as plt -from scipy.spatial import cKDTree, Voronoi -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent)) - -from VoronoiRoadMap.dijkstra_search import DijkstraSearch - -show_animation = True - - -class VoronoiRoadMapPlanner: - - def __init__(self): - # parameter - self.N_KNN = 10 # number of edge from one sampled point - self.MAX_EDGE_LEN = 30.0 # [m] Maximum edge length - - def planning(self, sx, sy, gx, gy, ox, oy, robot_radius): - obstacle_tree = cKDTree(np.vstack((ox, oy)).T) - - sample_x, sample_y = self.voronoi_sampling(sx, sy, gx, gy, ox, oy) - if show_animation: # pragma: no cover - plt.plot(sample_x, sample_y, ".b") - - road_map_info = self.generate_road_map_info( - sample_x, sample_y, robot_radius, obstacle_tree) - - rx, ry = DijkstraSearch(show_animation).search(sx, sy, gx, gy, - sample_x, sample_y, - road_map_info) - return rx, ry - - def is_collision(self, sx, sy, gx, gy, rr, obstacle_kd_tree): - x = sx - y = sy - dx = gx - sx - dy = gy - sy - yaw = math.atan2(gy - sy, gx - sx) - d = math.hypot(dx, dy) - - if d >= self.MAX_EDGE_LEN: - return True - - D = rr - n_step = round(d / D) - - for i in range(n_step): - dist, _ = obstacle_kd_tree.query([x, y]) - if dist <= rr: - return True # collision - x += D * math.cos(yaw) - y += D * math.sin(yaw) - - # goal point check - dist, _ = obstacle_kd_tree.query([gx, gy]) - if dist <= rr: - return True # collision - - return False # OK - - def generate_road_map_info(self, node_x, node_y, rr, obstacle_tree): - """ - Road map generation - - node_x: [m] x positions of sampled points - node_y: [m] y positions of sampled points - rr: Robot Radius[m] - obstacle_tree: KDTree object of obstacles - """ - - road_map = [] - n_sample = len(node_x) - node_tree = cKDTree(np.vstack((node_x, node_y)).T) - - for (i, ix, iy) in zip(range(n_sample), node_x, node_y): - - dists, indexes = node_tree.query([ix, iy], k=n_sample) - - edge_id = [] - - for ii in range(1, len(indexes)): - nx = node_x[indexes[ii]] - ny = node_y[indexes[ii]] - - if not self.is_collision(ix, iy, nx, ny, rr, obstacle_tree): - edge_id.append(indexes[ii]) - - if len(edge_id) >= self.N_KNN: - break - - road_map.append(edge_id) - - # plot_road_map(road_map, sample_x, sample_y) - - return road_map - - @staticmethod - def plot_road_map(road_map, sample_x, sample_y): # pragma: no cover - - for i, _ in enumerate(road_map): - for ii in range(len(road_map[i])): - ind = road_map[i][ii] - - plt.plot([sample_x[i], sample_x[ind]], - [sample_y[i], sample_y[ind]], "-k") - - @staticmethod - def voronoi_sampling(sx, sy, gx, gy, ox, oy): - oxy = np.vstack((ox, oy)).T - - # generate voronoi point - vor = Voronoi(oxy) - sample_x = [ix for [ix, _] in vor.vertices] - sample_y = [iy for [_, iy] in vor.vertices] - - sample_x.append(sx) - sample_y.append(sy) - sample_x.append(gx) - sample_y.append(gy) - - return sample_x, sample_y - - -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] - robot_size = 5.0 # [m] - - ox = [] - oy = [] - - for i in range(60): - ox.append(float(i)) - oy.append(0.0) - for i in range(60): - ox.append(60.0) - oy.append(float(i)) - for i in range(61): - ox.append(float(i)) - oy.append(60.0) - for i in range(61): - ox.append(0.0) - oy.append(float(i)) - for i in range(40): - ox.append(20.0) - oy.append(float(i)) - for i in range(40): - ox.append(40.0) - oy.append(60.0 - i) - - if show_animation: # pragma: no cover - plt.plot(ox, oy, ".k") - plt.plot(sx, sy, "^r") - plt.plot(gx, gy, "^c") - plt.grid(True) - plt.axis("equal") - - rx, ry = VoronoiRoadMapPlanner().planning(sx, sy, gx, gy, ox, oy, - robot_size) - - assert rx, 'Cannot found path' - - if show_animation: # pragma: no cover - plt.plot(rx, ry, "-r") - plt.pause(0.1) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathPlanning/WavefrontCPP/map/test.png b/PathPlanning/WavefrontCPP/map/test.png deleted file mode 100644 index 4abca0bf309..00000000000 Binary files a/PathPlanning/WavefrontCPP/map/test.png and /dev/null differ diff --git a/PathPlanning/WavefrontCPP/map/test_2.png b/PathPlanning/WavefrontCPP/map/test_2.png deleted file mode 100644 index 0d27fa9f958..00000000000 Binary files a/PathPlanning/WavefrontCPP/map/test_2.png and /dev/null differ diff --git a/PathPlanning/WavefrontCPP/map/test_3.png b/PathPlanning/WavefrontCPP/map/test_3.png deleted file mode 100644 index 1a50b87ccff..00000000000 Binary files a/PathPlanning/WavefrontCPP/map/test_3.png and /dev/null differ diff --git a/PathPlanning/WavefrontCPP/wavefront_coverage_path_planner.py b/PathPlanning/WavefrontCPP/wavefront_coverage_path_planner.py deleted file mode 100644 index c5a139454bb..00000000000 --- a/PathPlanning/WavefrontCPP/wavefront_coverage_path_planner.py +++ /dev/null @@ -1,218 +0,0 @@ -""" -Distance/Path Transform Wavefront Coverage Path Planner - -author: Todd Tang -paper: Planning paths of complete coverage of an unstructured environment - by a mobile robot - Zelinsky et.al. -link: https://pinkwink.kr/attachment/cfile3.uf@1354654A4E8945BD13FE77.pdf -""" - -import os -import sys - -import matplotlib.pyplot as plt -import numpy as np -from scipy import ndimage - -do_animation = True - - -def transform( - grid_map, src, distance_type='chessboard', - transform_type='path', alpha=0.01 -): - """transform - - calculating transform of transform_type from src - in given distance_type - - :param grid_map: 2d binary map - :param src: distance transform source - :param distance_type: type of distance used - :param transform_type: type of transform used - :param alpha: weight of Obstacle Transform used when using path_transform - """ - - n_rows, n_cols = grid_map.shape - - if n_rows == 0 or n_cols == 0: - sys.exit('Empty grid_map.') - - inc_order = [[0, 1], [1, 1], [1, 0], [1, -1], - [0, -1], [-1, -1], [-1, 0], [-1, 1]] - if distance_type == 'chessboard': - cost = [1, 1, 1, 1, 1, 1, 1, 1] - elif distance_type == 'eculidean': - cost = [1, np.sqrt(2), 1, np.sqrt(2), 1, np.sqrt(2), 1, np.sqrt(2)] - else: - sys.exit('Unsupported distance type.') - - transform_matrix = float('inf') * np.ones_like(grid_map, dtype=float) - transform_matrix[src[0], src[1]] = 0 - if transform_type == 'distance': - eT = np.zeros_like(grid_map) - elif transform_type == 'path': - eT = ndimage.distance_transform_cdt(1 - grid_map, distance_type) - else: - sys.exit('Unsupported transform type.') - - # set obstacle transform_matrix value to infinity - for i in range(n_rows): - for j in range(n_cols): - if grid_map[i][j] == 1.0: - transform_matrix[i][j] = float('inf') - is_visited = np.zeros_like(transform_matrix, dtype=bool) - is_visited[src[0], src[1]] = True - traversal_queue = [src] - calculated = set([(src[0] - 1) * n_cols + src[1]]) - - def is_valid_neighbor(g_i, g_j): - return 0 <= g_i < n_rows and 0 <= g_j < n_cols \ - and not grid_map[g_i][g_j] - - while traversal_queue: - i, j = traversal_queue.pop(0) - for k, inc in enumerate(inc_order): - ni = i + inc[0] - nj = j + inc[1] - if is_valid_neighbor(ni, nj): - is_visited[i][j] = True - - # update transform_matrix - transform_matrix[i][j] = min( - transform_matrix[i][j], - transform_matrix[ni][nj] + cost[k] + alpha * eT[ni][nj]) - - if not is_visited[ni][nj] \ - and ((ni - 1) * n_cols + nj) not in calculated: - traversal_queue.append((ni, nj)) - calculated.add((ni - 1) * n_cols + nj) - - return transform_matrix - - -def get_search_order_increment(start, goal): - if start[0] >= goal[0] and start[1] >= goal[1]: - order = [[1, 0], [0, 1], [-1, 0], [0, -1], - [1, 1], [1, -1], [-1, 1], [-1, -1]] - elif start[0] <= goal[0] and start[1] >= goal[1]: - order = [[-1, 0], [0, 1], [1, 0], [0, -1], - [-1, 1], [-1, -1], [1, 1], [1, -1]] - elif start[0] >= goal[0] and start[1] <= goal[1]: - order = [[1, 0], [0, -1], [-1, 0], [0, 1], - [1, -1], [-1, -1], [1, 1], [-1, 1]] - elif start[0] <= goal[0] and start[1] <= goal[1]: - order = [[-1, 0], [0, -1], [0, 1], [1, 0], - [-1, -1], [-1, 1], [1, -1], [1, 1]] - else: - sys.exit('get_search_order_increment: cannot determine \ - start=>goal increment order') - return order - - -def wavefront(transform_matrix, start, goal): - """wavefront - - performing wavefront coverage path planning - - :param transform_matrix: the transform matrix - :param start: start point of planning - :param goal: goal point of planning - """ - - path = [] - n_rows, n_cols = transform_matrix.shape - - def is_valid_neighbor(g_i, g_j): - is_i_valid_bounded = 0 <= g_i < n_rows - is_j_valid_bounded = 0 <= g_j < n_cols - if is_i_valid_bounded and is_j_valid_bounded: - return not is_visited[g_i][g_j] and \ - transform_matrix[g_i][g_j] != float('inf') - return False - - inc_order = get_search_order_increment(start, goal) - - current_node = start - is_visited = np.zeros_like(transform_matrix, dtype=bool) - - while current_node != goal: - i, j = current_node - path.append((i, j)) - is_visited[i][j] = True - - max_T = float('-inf') - i_max = (-1, -1) - i_last = 0 - for i_last in range(len(path)): - current_node = path[-1 - i_last] # get latest node in path - for ci, cj in inc_order: - ni, nj = current_node[0] + ci, current_node[1] + cj - if is_valid_neighbor(ni, nj) and \ - transform_matrix[ni][nj] > max_T: - i_max = (ni, nj) - max_T = transform_matrix[ni][nj] - - if i_max != (-1, -1): - break - - if i_max == (-1, -1): - break - else: - current_node = i_max - if i_last != 0: - print('backtracing to', current_node) - path.append(goal) - - return path - - -def visualize_path(grid_map, start, goal, path): # pragma: no cover - oy, ox = start - gy, gx = goal - px, py = np.transpose(np.flipud(np.fliplr(path))) - - if not do_animation: - plt.imshow(grid_map, cmap='Greys') - plt.plot(ox, oy, "-xy") - plt.plot(px, py, "-r") - plt.plot(gx, gy, "-pg") - plt.show() - else: - for ipx, ipy in zip(px, py): - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.imshow(grid_map, cmap='Greys') - plt.plot(ox, oy, "-xb") - plt.plot(px, py, "-r") - plt.plot(gx, gy, "-pg") - plt.plot(ipx, ipy, "or") - plt.axis("equal") - plt.grid(True) - plt.pause(0.1) - - -def main(): - dir_path = os.path.dirname(os.path.realpath(__file__)) - img = plt.imread(os.path.join(dir_path, 'map', 'test.png')) - img = 1 - img # revert pixel values - - start = (43, 0) - goal = (0, 0) - - # distance transform wavefront - DT = transform(img, goal, transform_type='distance') - DT_path = wavefront(DT, start, goal) - visualize_path(img, start, goal, DT_path) - - # path transform wavefront - PT = transform(img, goal, transform_type='path', alpha=0.01) - PT_path = wavefront(PT, start, goal) - visualize_path(img, start, goal, PT_path) - - -if __name__ == "__main__": - main() diff --git a/PathPlanning/__init__.py b/PathPlanning/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathTracking/__init__.py b/PathTracking/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathTracking/cgmres_nmpc/cgmres_nmpc.py b/PathTracking/cgmres_nmpc/cgmres_nmpc.py deleted file mode 100644 index a582c9da810..00000000000 --- a/PathTracking/cgmres_nmpc/cgmres_nmpc.py +++ /dev/null @@ -1,616 +0,0 @@ -""" - -Nonlinear MPC simulation with CGMRES - -author Atsushi Sakai (@Atsushi_twi) - -Ref: -Shunichi09/nonlinear_control: Implementing the nonlinear model predictive -control, sliding mode control https://github.com/Shunichi09/PythonLinearNonlinearControl - -""" - -from math import cos, sin, radians, atan2 - -import matplotlib.pyplot as plt -import numpy as np - -U_A_MAX = 1.0 -U_OMEGA_MAX = radians(45.0) -PHI_V = 0.01 -PHI_OMEGA = 0.01 -WB = 0.25 # [m] wheel base - -show_animation = True - - -def differential_model(v, yaw, u_1, u_2): - dx = cos(yaw) * v - dy = sin(yaw) * v - dv = u_1 - # tangent is not good for nonlinear optimization - d_yaw = v / WB * sin(u_2) - - return dx, dy, d_yaw, dv - - -class TwoWheeledSystem: - - def __init__(self, init_x, init_y, init_yaw, init_v): - self.x = init_x - self.y = init_y - self.yaw = init_yaw - self.v = init_v - self.history_x = [init_x] - self.history_y = [init_y] - self.history_yaw = [init_yaw] - self.history_v = [init_v] - - def update_state(self, u_1, u_2, dt=0.01): - dx, dy, d_yaw, dv = differential_model(self.v, self.yaw, u_1, u_2) - - self.x += dt * dx - self.y += dt * dy - self.yaw += dt * d_yaw - self.v += dt * dv - - # save - self.history_x.append(self.x) - self.history_y.append(self.y) - self.history_yaw.append(self.yaw) - self.history_v.append(self.v) - - -class NMPCSimulatorSystem: - - def calc_predict_and_adjoint_state(self, x, y, yaw, v, u_1s, u_2s, N, dt): - # by using state equation - x_s, y_s, yaw_s, v_s = self._calc_predict_states( - x, y, yaw, v, u_1s, u_2s, N, dt) - # by using adjoint equation - lam_1s, lam_2s, lam_3s, lam_4s = self._calc_adjoint_states( - x_s, y_s, yaw_s, v_s, u_2s, N, dt) - - return x_s, y_s, yaw_s, v_s, lam_1s, lam_2s, lam_3s, lam_4s - - def _calc_predict_states(self, x, y, yaw, v, u_1s, u_2s, N, dt): - x_s = [x] - y_s = [y] - yaw_s = [yaw] - v_s = [v] - - for i in range(N): - temp_x_1, temp_x_2, temp_x_3, temp_x_4 = self._predict_state_with_oylar( - x_s[i], y_s[i], yaw_s[i], v_s[i], u_1s[i], u_2s[i], dt) - x_s.append(temp_x_1) - y_s.append(temp_x_2) - yaw_s.append(temp_x_3) - v_s.append(temp_x_4) - - return x_s, y_s, yaw_s, v_s - - def _calc_adjoint_states(self, x_s, y_s, yaw_s, v_s, u_2s, N, dt): - lam_1s = [x_s[-1]] - lam_2s = [y_s[-1]] - lam_3s = [yaw_s[-1]] - lam_4s = [v_s[-1]] - - # backward adjoint state calc - for i in range(N - 1, 0, -1): - temp_lam_1, temp_lam_2, temp_lam_3, temp_lam_4 = self._adjoint_state_with_oylar( - yaw_s[i], v_s[i], lam_1s[0], lam_2s[0], lam_3s[0], lam_4s[0], - u_2s[i], dt) - lam_1s.insert(0, temp_lam_1) - lam_2s.insert(0, temp_lam_2) - lam_3s.insert(0, temp_lam_3) - lam_4s.insert(0, temp_lam_4) - - return lam_1s, lam_2s, lam_3s, lam_4s - - @staticmethod - def _predict_state_with_oylar(x, y, yaw, v, u_1, u_2, dt): - - dx, dy, dyaw, dv = differential_model( - v, yaw, u_1, u_2) - - next_x_1 = x + dt * dx - next_x_2 = y + dt * dy - next_x_3 = yaw + dt * dyaw - next_x_4 = v + dt * dv - - return next_x_1, next_x_2, next_x_3, next_x_4 - - @staticmethod - def _adjoint_state_with_oylar(yaw, v, lam_1, lam_2, lam_3, lam_4, u_2, dt): - - # ∂H/∂x - pre_lam_1 = lam_1 + dt * 0.0 - pre_lam_2 = lam_2 + dt * 0.0 - tmp1 = - lam_1 * sin(yaw) * v + lam_2 * cos(yaw) * v - pre_lam_3 = lam_3 + dt * tmp1 - tmp2 = lam_1 * cos(yaw) + lam_2 * sin(yaw) + lam_3 * sin(u_2) / WB - pre_lam_4 = lam_4 + dt * tmp2 - - return pre_lam_1, pre_lam_2, pre_lam_3, pre_lam_4 - - -class NMPCControllerCGMRES: - """ - Attributes - ------------ - zeta : float - gain of optimal answer stability - ht : float - update value of NMPC this should be decided by zeta - tf : float - predict time - alpha : float - gain of predict time - N : int - predict step, discrete value - threshold : float - cgmres's threshold value - input_num : int - system input length, this should include dummy u and constraint variables - max_iteration : int - decide by the solved matrix size - simulator : NMPCSimulatorSystem class - u_1s : list of float - estimated optimal system input - u_2s : list of float - estimated optimal system input - dummy_u_1s : list of float - estimated dummy input - dummy_u_2s : list of float - estimated dummy input - raw_1s : list of float - estimated constraint variable - raw_2s : list of float - estimated constraint variable - history_u_1 : list of float - time history of actual system input - history_u_2 : list of float - time history of actual system input - history_dummy_u_1 : list of float - time history of actual dummy u_1 - history_dummy_u_2 : list of float - time history of actual dummy u_2 - history_raw_1 : list of float - time history of actual raw_1 - history_raw_2 : list of float - time history of actual raw_2 - history_f : list of float - time history of error of optimal - """ - - def __init__(self): - # parameters - self.zeta = 100. # stability gain - self.ht = 0.01 # difference approximation tick - self.tf = 3.0 # final time - self.alpha = 0.5 # time gain - self.N = 10 # division number - self.threshold = 0.001 - self.input_num = 6 # input number of dummy, constraints - self.max_iteration = self.input_num * self.N - - # simulator - self.simulator = NMPCSimulatorSystem() - - # initial input, initialize as 1.0 - self.u_1s = np.ones(self.N) - self.u_2s = np.ones(self.N) - self.dummy_u_1s = np.ones(self.N) - self.dummy_u_2s = np.ones(self.N) - self.raw_1s = np.zeros(self.N) - self.raw_2s = np.zeros(self.N) - - self.history_u_1 = [] - self.history_u_2 = [] - self.history_dummy_u_1 = [] - self.history_dummy_u_2 = [] - self.history_raw_1 = [] - self.history_raw_2 = [] - self.history_f = [] - - def calc_input(self, x, y, yaw, v, time): - - # calculating sampling time - dt = self.tf * (1. - np.exp(-self.alpha * time)) / float(self.N) - - # x_dot - x_1_dot, x_2_dot, x_3_dot, x_4_dot = differential_model( - v, yaw, self.u_1s[0], self.u_2s[0]) - - dx_1 = x_1_dot * self.ht - dx_2 = x_2_dot * self.ht - dx_3 = x_3_dot * self.ht - dx_4 = x_4_dot * self.ht - - x_s, y_s, yaw_s, v_s, lam_1s, lam_2s, lam_3s, lam_4s = self.simulator.calc_predict_and_adjoint_state( - x + dx_1, y + dx_2, yaw + dx_3, v + dx_4, self.u_1s, self.u_2s, - self.N, dt) - - # Fxt:F(U,x+hx˙,t+h) - Fxt = self._calc_f(v_s, lam_3s, lam_4s, - self.u_1s, self.u_2s, self.dummy_u_1s, - self.dummy_u_2s, - self.raw_1s, self.raw_2s, self.N) - - # F:F(U,x,t) - x_s, y_s, yaw_s, v_s, lam_1s, lam_2s, lam_3s, lam_4s = self.simulator.calc_predict_and_adjoint_state( - x, y, yaw, v, self.u_1s, self.u_2s, self.N, dt) - - F = self._calc_f(v_s, lam_3s, lam_4s, - self.u_1s, self.u_2s, self.dummy_u_1s, self.dummy_u_2s, - self.raw_1s, self.raw_2s, self.N) - - right = -self.zeta * F - ((Fxt - F) / self.ht) - - du_1 = self.u_1s * self.ht - du_2 = self.u_2s * self.ht - ddummy_u_1 = self.dummy_u_1s * self.ht - ddummy_u_2 = self.dummy_u_2s * self.ht - draw_1 = self.raw_1s * self.ht - draw_2 = self.raw_2s * self.ht - - x_s, y_s, yaw_s, v_s, lam_1s, lam_2s, lam_3s, lam_4s = self.simulator.calc_predict_and_adjoint_state( - x + dx_1, y + dx_2, yaw + dx_3, v + dx_4, self.u_1s + du_1, - self.u_2s + du_2, self.N, dt) - - # Fuxt:F(U+hdU(0),x+hx˙,t+h) - Fuxt = self._calc_f(v_s, lam_3s, lam_4s, - self.u_1s + du_1, self.u_2s + du_2, - self.dummy_u_1s + ddummy_u_1, - self.dummy_u_2s + ddummy_u_2, - self.raw_1s + draw_1, self.raw_2s + draw_2, self.N) - - left = ((Fuxt - Fxt) / self.ht) - - # calculating cgmres - r0 = right - left - r0_norm = np.linalg.norm(r0) - - vs = np.zeros((self.max_iteration, self.max_iteration + 1)) - vs[:, 0] = r0 / r0_norm - - hs = np.zeros((self.max_iteration + 1, self.max_iteration + 1)) - - # in this case the state is 3(u and dummy_u) - e = np.zeros((self.max_iteration + 1, 1)) - e[0] = 1.0 - - ys_pre = None - - du_1_new, du_2_new, draw_1_new, draw_2_new = None, None, None, None - ddummy_u_1_new, ddummy_u_2_new = None, None - - for i in range(self.max_iteration): - du_1 = vs[::self.input_num, i] * self.ht - du_2 = vs[1::self.input_num, i] * self.ht - ddummy_u_1 = vs[2::self.input_num, i] * self.ht - ddummy_u_2 = vs[3::self.input_num, i] * self.ht - draw_1 = vs[4::self.input_num, i] * self.ht - draw_2 = vs[5::self.input_num, i] * self.ht - - x_s, y_s, yaw_s, v_s, lam_1s, lam_2s, lam_3s, lam_4s = self.simulator.calc_predict_and_adjoint_state( - x + dx_1, y + dx_2, yaw + dx_3, v + dx_4, self.u_1s + du_1, - self.u_2s + du_2, self.N, dt) - - Fuxt = self._calc_f(v_s, lam_3s, lam_4s, - self.u_1s + du_1, self.u_2s + du_2, - self.dummy_u_1s + ddummy_u_1, - self.dummy_u_2s + ddummy_u_2, - self.raw_1s + draw_1, self.raw_2s + draw_2, - self.N) - - Av = ((Fuxt - Fxt) / self.ht) - - sum_Av = np.zeros(self.max_iteration) - - # Gram–Schmidt orthonormalization - for j in range(i + 1): - hs[j, i] = np.dot(Av, vs[:, j]) - sum_Av = sum_Av + hs[j, i] * vs[:, j] - - v_est = Av - sum_Av - - hs[i + 1, i] = np.linalg.norm(v_est) - - vs[:, i + 1] = v_est / hs[i + 1, i] - - inv_hs = np.linalg.pinv(hs[:i + 1, :i]) - ys = np.dot(inv_hs, r0_norm * e[:i + 1]) - - judge_value = r0_norm * e[:i + 1] - np.dot(hs[:i + 1, :i], ys[:i]) - - flag1 = np.linalg.norm(judge_value) < self.threshold - - flag2 = i == self.max_iteration - 1 - if flag1 or flag2: - update_val = np.dot(vs[:, :i - 1], ys_pre[:i - 1]).flatten() - du_1_new = du_1 + update_val[::self.input_num] - du_2_new = du_2 + update_val[1::self.input_num] - ddummy_u_1_new = ddummy_u_1 + update_val[2::self.input_num] - ddummy_u_2_new = ddummy_u_2 + update_val[3::self.input_num] - draw_1_new = draw_1 + update_val[4::self.input_num] - draw_2_new = draw_2 + update_val[5::self.input_num] - break - - ys_pre = ys - - # update input - self.u_1s += du_1_new * self.ht - self.u_2s += du_2_new * self.ht - self.dummy_u_1s += ddummy_u_1_new * self.ht - self.dummy_u_2s += ddummy_u_2_new * self.ht - self.raw_1s += draw_1_new * self.ht - self.raw_2s += draw_2_new * self.ht - - x_s, y_s, yaw_s, v_s, lam_1s, lam_2s, lam_3s, lam_4s = self.simulator.calc_predict_and_adjoint_state( - x, y, yaw, v, self.u_1s, self.u_2s, self.N, dt) - - F = self._calc_f(v_s, lam_3s, lam_4s, - self.u_1s, self.u_2s, self.dummy_u_1s, self.dummy_u_2s, - self.raw_1s, self.raw_2s, self.N) - - print("norm(F) = {0}".format(np.linalg.norm(F))) - - # for save - self.history_f.append(np.linalg.norm(F)) - self.history_u_1.append(self.u_1s[0]) - self.history_u_2.append(self.u_2s[0]) - self.history_dummy_u_1.append(self.dummy_u_1s[0]) - self.history_dummy_u_2.append(self.dummy_u_2s[0]) - self.history_raw_1.append(self.raw_1s[0]) - self.history_raw_2.append(self.raw_2s[0]) - - return self.u_1s, self.u_2s - - @staticmethod - def _calc_f(v_s, lam_3s, lam_4s, u_1s, u_2s, dummy_u_1s, dummy_u_2s, - raw_1s, raw_2s, N): - - F = [] - for i in range(N): - # ∂H/∂u(xi, ui, λi) - F.append(u_1s[i] + lam_4s[i] + 2.0 * raw_1s[i] * u_1s[i]) - F.append(u_2s[i] + lam_3s[i] * v_s[i] / - WB * cos(u_2s[i]) ** 2 + 2.0 * raw_2s[i] * u_2s[i]) - F.append(-PHI_V + 2.0 * raw_1s[i] * dummy_u_1s[i]) - F.append(-PHI_OMEGA + 2.0 * raw_2s[i] * dummy_u_2s[i]) - - # C(xi, ui, λi) - F.append(u_1s[i] ** 2 + dummy_u_1s[i] ** 2 - U_A_MAX ** 2) - F.append(u_2s[i] ** 2 + dummy_u_2s[i] ** 2 - U_OMEGA_MAX ** 2) - - return np.array(F) - - -def plot_figures(plant_system, controller, iteration_num, - dt): # pragma: no cover - # figure - # time history - fig_p = plt.figure() - fig_u = plt.figure() - fig_f = plt.figure() - - # trajectory - fig_t = plt.figure() - fig_trajectory = fig_t.add_subplot(111) - fig_trajectory.set_aspect('equal') - - x_1_fig = fig_p.add_subplot(411) - x_2_fig = fig_p.add_subplot(412) - x_3_fig = fig_p.add_subplot(413) - x_4_fig = fig_p.add_subplot(414) - - u_1_fig = fig_u.add_subplot(411) - u_2_fig = fig_u.add_subplot(412) - dummy_1_fig = fig_u.add_subplot(413) - dummy_2_fig = fig_u.add_subplot(414) - - raw_1_fig = fig_f.add_subplot(311) - raw_2_fig = fig_f.add_subplot(312) - f_fig = fig_f.add_subplot(313) - - x_1_fig.plot(np.arange(iteration_num) * dt, plant_system.history_x) - x_1_fig.set_xlabel("time [s]") - x_1_fig.set_ylabel("x") - - x_2_fig.plot(np.arange(iteration_num) * dt, plant_system.history_y) - x_2_fig.set_xlabel("time [s]") - x_2_fig.set_ylabel("y") - - x_3_fig.plot(np.arange(iteration_num) * dt, plant_system.history_yaw) - x_3_fig.set_xlabel("time [s]") - x_3_fig.set_ylabel("yaw") - - x_4_fig.plot(np.arange(iteration_num) * dt, plant_system.history_v) - x_4_fig.set_xlabel("time [s]") - x_4_fig.set_ylabel("v") - - u_1_fig.plot(np.arange(iteration_num - 1) * dt, controller.history_u_1) - u_1_fig.set_xlabel("time [s]") - u_1_fig.set_ylabel("u_a") - - u_2_fig.plot(np.arange(iteration_num - 1) * dt, controller.history_u_2) - u_2_fig.set_xlabel("time [s]") - u_2_fig.set_ylabel("u_omega") - - dummy_1_fig.plot(np.arange(iteration_num - 1) * - dt, controller.history_dummy_u_1) - dummy_1_fig.set_xlabel("time [s]") - dummy_1_fig.set_ylabel("dummy u_1") - - dummy_2_fig.plot(np.arange(iteration_num - 1) * - dt, controller.history_dummy_u_2) - dummy_2_fig.set_xlabel("time [s]") - dummy_2_fig.set_ylabel("dummy u_2") - - raw_1_fig.plot(np.arange(iteration_num - 1) * dt, controller.history_raw_1) - raw_1_fig.set_xlabel("time [s]") - raw_1_fig.set_ylabel("raw_1") - - raw_2_fig.plot(np.arange(iteration_num - 1) * dt, controller.history_raw_2) - raw_2_fig.set_xlabel("time [s]") - raw_2_fig.set_ylabel("raw_2") - - f_fig.plot(np.arange(iteration_num - 1) * dt, controller.history_f) - f_fig.set_xlabel("time [s]") - f_fig.set_ylabel("optimal error") - - fig_trajectory.plot(plant_system.history_x, - plant_system.history_y, "-r") - fig_trajectory.set_xlabel("x [m]") - fig_trajectory.set_ylabel("y [m]") - fig_trajectory.axis("equal") - - # start state - plot_car(plant_system.history_x[0], - plant_system.history_y[0], - plant_system.history_yaw[0], - controller.history_u_2[0], - ) - - # goal state - plot_car(0.0, 0.0, 0.0, 0.0) - - plt.show() - - -def plot_car(x, y, yaw, steer=0.0, truck_color="-k"): # pragma: no cover - - # Vehicle parameters - LENGTH = 0.4 # [m] - WIDTH = 0.2 # [m] - BACK_TO_WHEEL = 0.1 # [m] - WHEEL_LEN = 0.03 # [m] - WHEEL_WIDTH = 0.02 # [m] - TREAD = 0.07 # [m] - - outline = np.array( - [[-BACK_TO_WHEEL, (LENGTH - BACK_TO_WHEEL), (LENGTH - BACK_TO_WHEEL), - -BACK_TO_WHEEL, -BACK_TO_WHEEL], - [WIDTH / 2, WIDTH / 2, - WIDTH / 2, -WIDTH / 2, WIDTH / 2]]) - - fr_wheel = np.array( - [[WHEEL_LEN, -WHEEL_LEN, -WHEEL_LEN, WHEEL_LEN, WHEEL_LEN], - [-WHEEL_WIDTH - TREAD, -WHEEL_WIDTH - TREAD, WHEEL_WIDTH - - TREAD, WHEEL_WIDTH - TREAD, -WHEEL_WIDTH - TREAD]]) - - rr_wheel = np.copy(fr_wheel) - - fl_wheel = np.copy(fr_wheel) - fl_wheel[1, :] *= -1 - rl_wheel = np.copy(rr_wheel) - rl_wheel[1, :] *= -1 - - Rot1 = np.array([[cos(yaw), sin(yaw)], - [-sin(yaw), cos(yaw)]]) - Rot2 = np.array([[cos(steer), sin(steer)], - [-sin(steer), cos(steer)]]) - - fr_wheel = (fr_wheel.T.dot(Rot2)).T - fl_wheel = (fl_wheel.T.dot(Rot2)).T - fr_wheel[0, :] += WB - fl_wheel[0, :] += WB - - fr_wheel = (fr_wheel.T.dot(Rot1)).T - fl_wheel = (fl_wheel.T.dot(Rot1)).T - - outline = (outline.T.dot(Rot1)).T - rr_wheel = (rr_wheel.T.dot(Rot1)).T - rl_wheel = (rl_wheel.T.dot(Rot1)).T - - outline[0, :] += x - outline[1, :] += y - fr_wheel[0, :] += x - fr_wheel[1, :] += y - rr_wheel[0, :] += x - rr_wheel[1, :] += y - fl_wheel[0, :] += x - fl_wheel[1, :] += y - rl_wheel[0, :] += x - rl_wheel[1, :] += y - - plt.plot(np.array(outline[0, :]).flatten(), - np.array(outline[1, :]).flatten(), truck_color) - plt.plot(np.array(fr_wheel[0, :]).flatten(), - np.array(fr_wheel[1, :]).flatten(), truck_color) - plt.plot(np.array(rr_wheel[0, :]).flatten(), - np.array(rr_wheel[1, :]).flatten(), truck_color) - plt.plot(np.array(fl_wheel[0, :]).flatten(), - np.array(fl_wheel[1, :]).flatten(), truck_color) - plt.plot(np.array(rl_wheel[0, :]).flatten(), - np.array(rl_wheel[1, :]).flatten(), truck_color) - plt.plot(x, y, "*") - - -def animation(plant, controller, dt): - skip = 2 # skip index for animation - - for t in range(1, len(controller.history_u_1), skip): - x = plant.history_x[t] - y = plant.history_y[t] - yaw = plant.history_yaw[t] - v = plant.history_v[t] - accel = controller.history_u_1[t] - time = t * dt - - if abs(v) <= 0.01: - steer = 0.0 - else: - steer = atan2(controller.history_u_2[t] * WB / v, 1.0) - - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(plant.history_x, plant.history_y, "-r", label="trajectory") - plot_car(x, y, yaw, steer=steer) - plt.axis("equal") - plt.grid(True) - plt.title("Time[s]:" + str(round(time, 2)) + - ", accel[m/s]:" + str(round(accel, 2)) + - ", speed[km/h]:" + str(round(v * 3.6, 2))) - plt.pause(0.0001) - - plt.close("all") - - -def main(): - # simulation time - dt = 0.1 - iteration_time = 150.0 # [s] - - init_x = -4.5 - init_y = -2.5 - init_yaw = radians(45.0) - init_v = -1.0 - - # plant - plant_system = TwoWheeledSystem( - init_x, init_y, init_yaw, init_v) - - # controller - controller = NMPCControllerCGMRES() - - iteration_num = int(iteration_time / dt) - for i in range(1, iteration_num): - time = float(i) * dt - # make input - u_1s, u_2s = controller.calc_input( - plant_system.x, plant_system.y, plant_system.yaw, plant_system.v, - time) - # update state - plant_system.update_state(u_1s[0], u_2s[0]) - - if show_animation: # pragma: no cover - animation(plant_system, controller, dt) - plot_figures(plant_system, controller, iteration_num, dt) - - -if __name__ == "__main__": - main() diff --git a/PathTracking/lqr_speed_steer_control/lqr_speed_steer_control.py b/PathTracking/lqr_speed_steer_control/lqr_speed_steer_control.py deleted file mode 100644 index 5831d02d300..00000000000 --- a/PathTracking/lqr_speed_steer_control/lqr_speed_steer_control.py +++ /dev/null @@ -1,321 +0,0 @@ -""" - -Path tracking simulation with LQR speed and steering control - -author Atsushi Sakai (@Atsushi_twi) - -""" -import math -import sys -import matplotlib.pyplot as plt -import numpy as np -import scipy.linalg as la -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) -from utils.angle import angle_mod -from PathPlanning.CubicSpline import cubic_spline_planner - -# === Parameters ===== - -# LQR parameter -lqr_Q = np.eye(5) -lqr_R = np.eye(2) -dt = 0.1 # time tick[s] -L = 0.5 # Wheel base of the vehicle [m] -max_steer = np.deg2rad(45.0) # maximum steering angle[rad] - -show_animation = True - - -class State: - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - - -def update(state, a, delta): - - if delta >= max_steer: - delta = max_steer - if delta <= - max_steer: - delta = - max_steer - - state.x = state.x + state.v * math.cos(state.yaw) * dt - state.y = state.y + state.v * math.sin(state.yaw) * dt - state.yaw = state.yaw + state.v / L * math.tan(delta) * dt - state.v = state.v + a * dt - - return state - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def solve_dare(A, B, Q, R): - """ - solve a discrete time_Algebraic Riccati equation (DARE) - """ - x = Q - x_next = Q - max_iter = 150 - eps = 0.01 - - for i in range(max_iter): - x_next = A.T @ x @ A - A.T @ x @ B @ \ - la.inv(R + B.T @ x @ B) @ B.T @ x @ A + Q - if (abs(x_next - x)).max() < eps: - break - x = x_next - - return x_next - - -def dlqr(A, B, Q, R): - """Solve the discrete time lqr controller. - x[k+1] = A x[k] + B u[k] - cost = sum x[k].T*Q*x[k] + u[k].T*R*u[k] - # ref Bertsekas, p.151 - """ - - # first, try to solve the ricatti equation - X = solve_dare(A, B, Q, R) - - # compute the LQR gain - K = la.inv(B.T @ X @ B + R) @ (B.T @ X @ A) - - eig_result = la.eig(A - B @ K) - - return K, X, eig_result[0] - - -def lqr_speed_steering_control(state, cx, cy, cyaw, ck, pe, pth_e, sp, Q, R): - ind, e = calc_nearest_index(state, cx, cy, cyaw) - - tv = sp[ind] - - k = ck[ind] - v = state.v - th_e = pi_2_pi(state.yaw - cyaw[ind]) - - # A = [1.0, dt, 0.0, 0.0, 0.0 - # 0.0, 0.0, v, 0.0, 0.0] - # 0.0, 0.0, 1.0, dt, 0.0] - # 0.0, 0.0, 0.0, 0.0, 0.0] - # 0.0, 0.0, 0.0, 0.0, 1.0] - A = np.zeros((5, 5)) - A[0, 0] = 1.0 - A[0, 1] = dt - A[1, 2] = v - A[2, 2] = 1.0 - A[2, 3] = dt - A[4, 4] = 1.0 - - # B = [0.0, 0.0 - # 0.0, 0.0 - # 0.0, 0.0 - # v/L, 0.0 - # 0.0, dt] - B = np.zeros((5, 2)) - B[3, 0] = v / L - B[4, 1] = dt - - K, _, _ = dlqr(A, B, Q, R) - - # state vector - # x = [e, dot_e, th_e, dot_th_e, delta_v] - # e: lateral distance to the path - # dot_e: derivative of e - # th_e: angle difference to the path - # dot_th_e: derivative of th_e - # delta_v: difference between current speed and target speed - x = np.zeros((5, 1)) - x[0, 0] = e - x[1, 0] = (e - pe) / dt - x[2, 0] = th_e - x[3, 0] = (th_e - pth_e) / dt - x[4, 0] = v - tv - - # input vector - # u = [delta, accel] - # delta: steering angle - # accel: acceleration - ustar = -K @ x - - # calc steering input - ff = math.atan2(L * k, 1) # feedforward steering angle - fb = pi_2_pi(ustar[0, 0]) # feedback steering angle - delta = ff + fb - - # calc accel input - accel = ustar[1, 0] - - return delta, ind, e, th_e, accel - - -def calc_nearest_index(state, cx, cy, cyaw): - dx = [state.x - icx for icx in cx] - dy = [state.y - icy for icy in cy] - - d = [idx ** 2 + idy ** 2 for (idx, idy) in zip(dx, dy)] - - mind = min(d) - - ind = d.index(mind) - - mind = math.sqrt(mind) - - dxl = cx[ind] - state.x - dyl = cy[ind] - state.y - - angle = pi_2_pi(cyaw[ind] - math.atan2(dyl, dxl)) - if angle < 0: - mind *= -1 - - return ind, mind - - -def do_simulation(cx, cy, cyaw, ck, speed_profile, goal): - T = 500.0 # max simulation time - goal_dis = 0.3 - stop_speed = 0.05 - - state = State(x=-0.0, y=-0.0, yaw=0.0, v=0.0) - - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - - e, e_th = 0.0, 0.0 - - while T >= time: - dl, target_ind, e, e_th, ai = lqr_speed_steering_control( - state, cx, cy, cyaw, ck, e, e_th, speed_profile, lqr_Q, lqr_R) - - state = update(state, ai, dl) - - if abs(state.v) <= stop_speed: - target_ind += 1 - - time = time + dt - - # check goal - dx = state.x - goal[0] - dy = state.y - goal[1] - if math.hypot(dx, dy) <= goal_dis: - print("Goal") - break - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - - if target_ind % 1 == 0 and show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(cx, cy, "-r", label="course") - plt.plot(x, y, "ob", label="trajectory") - plt.plot(cx[target_ind], cy[target_ind], "xg", label="target") - plt.axis("equal") - plt.grid(True) - plt.title("speed[km/h]:" + str(round(state.v * 3.6, 2)) - + ",target index:" + str(target_ind)) - plt.pause(0.0001) - - return t, x, y, yaw, v - - -def calc_speed_profile(cyaw, target_speed): - speed_profile = [target_speed] * len(cyaw) - - direction = 1.0 - - # Set stop point - for i in range(len(cyaw) - 1): - dyaw = abs(cyaw[i + 1] - cyaw[i]) - switch = math.pi / 4.0 <= dyaw < math.pi / 2.0 - - if switch: - direction *= -1 - - if direction != 1.0: - speed_profile[i] = - target_speed - else: - speed_profile[i] = target_speed - - if switch: - speed_profile[i] = 0.0 - - # speed down - for i in range(40): - speed_profile[-i] = target_speed / (50 - i) - if speed_profile[-i] <= 1.0 / 3.6: - speed_profile[-i] = 1.0 / 3.6 - - return speed_profile - - -def main(): - print("LQR steering control tracking start!!") - ax = [0.0, 6.0, 12.5, 10.0, 17.5, 20.0, 25.0] - ay = [0.0, -3.0, -5.0, 6.5, 3.0, 0.0, 0.0] - goal = [ax[-1], ay[-1]] - - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=0.1) - target_speed = 10.0 / 3.6 # simulation parameter km/h -> m/s - - sp = calc_speed_profile(cyaw, target_speed) - - t, x, y, yaw, v = do_simulation(cx, cy, cyaw, ck, sp, goal) - - if show_animation: # pragma: no cover - plt.close() - plt.subplots(1) - plt.plot(ax, ay, "xb", label="waypoints") - plt.plot(cx, cy, "-r", label="target course") - plt.plot(x, y, "-g", label="tracking") - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - plt.subplots(1) - - plt.plot(t, np.array(v)*3.6, label="speed") - plt.grid(True) - plt.xlabel("Time [sec]") - plt.ylabel("Speed [m/s]") - plt.legend() - - plt.subplots(1) - plt.plot(s, [np.rad2deg(iyaw) for iyaw in cyaw], "-r", label="yaw") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("yaw angle[deg]") - - plt.subplots(1) - plt.plot(s, ck, "-r", label="curvature") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("curvature [1/m]") - - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathTracking/lqr_steer_control/__init__.py b/PathTracking/lqr_steer_control/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathTracking/lqr_steer_control/lqr_steer_control.py b/PathTracking/lqr_steer_control/lqr_steer_control.py deleted file mode 100644 index 3c066917ff7..00000000000 --- a/PathTracking/lqr_steer_control/lqr_steer_control.py +++ /dev/null @@ -1,291 +0,0 @@ -""" - -Path tracking simulation with LQR steering control and PID speed control. - -author Atsushi Sakai (@Atsushi_twi) - -""" -import scipy.linalg as la -import matplotlib.pyplot as plt -import math -import numpy as np -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) -from utils.angle import angle_mod -from PathPlanning.CubicSpline import cubic_spline_planner - -Kp = 1.0 # speed proportional gain - -# LQR parameter -Q = np.eye(4) -R = np.eye(1) - -# parameters -dt = 0.1 # time tick[s] -L = 0.5 # Wheelbase of the vehicle [m] -max_steer = np.deg2rad(45.0) # maximum steering angle[rad] - -show_animation = True -# show_animation = False - - -class State: - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - - -def update(state, a, delta): - - if delta >= max_steer: - delta = max_steer - if delta <= - max_steer: - delta = - max_steer - - state.x = state.x + state.v * math.cos(state.yaw) * dt - state.y = state.y + state.v * math.sin(state.yaw) * dt - state.yaw = state.yaw + state.v / L * math.tan(delta) * dt - state.v = state.v + a * dt - - return state - - -def pid_control(target, current): - a = Kp * (target - current) - - return a - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def solve_DARE(A, B, Q, R): - """ - solve a discrete time_Algebraic Riccati equation (DARE) - """ - X = Q - Xn = Q - max_iter = 150 - eps = 0.01 - - for i in range(max_iter): - Xn = A.T @ X @ A - A.T @ X @ B @ \ - la.inv(R + B.T @ X @ B) @ B.T @ X @ A + Q - if (abs(Xn - X)).max() < eps: - break - X = Xn - - return Xn - - -def dlqr(A, B, Q, R): - """Solve the discrete time lqr controller. - x[k+1] = A x[k] + B u[k] - cost = sum x[k].T*Q*x[k] + u[k].T*R*u[k] - # ref Bertsekas, p.151 - """ - - # first, try to solve the ricatti equation - X = solve_DARE(A, B, Q, R) - - # compute the LQR gain - K = la.inv(B.T @ X @ B + R) @ (B.T @ X @ A) - - eigVals, eigVecs = la.eig(A - B @ K) - - return K, X, eigVals - - -def lqr_steering_control(state, cx, cy, cyaw, ck, pe, pth_e): - ind, e = calc_nearest_index(state, cx, cy, cyaw) - - k = ck[ind] - v = state.v - th_e = pi_2_pi(state.yaw - cyaw[ind]) - - A = np.zeros((4, 4)) - A[0, 0] = 1.0 - A[0, 1] = dt - A[1, 2] = v - A[2, 2] = 1.0 - A[2, 3] = dt - # print(A) - - B = np.zeros((4, 1)) - B[3, 0] = v / L - - K, _, _ = dlqr(A, B, Q, R) - - x = np.zeros((4, 1)) - - x[0, 0] = e - x[1, 0] = (e - pe) / dt - x[2, 0] = th_e - x[3, 0] = (th_e - pth_e) / dt - - ff = math.atan2(L * k, 1) - fb = pi_2_pi((-K @ x)[0, 0]) - - delta = ff + fb - - return delta, ind, e, th_e - - -def calc_nearest_index(state, cx, cy, cyaw): - dx = [state.x - icx for icx in cx] - dy = [state.y - icy for icy in cy] - - d = [idx ** 2 + idy ** 2 for (idx, idy) in zip(dx, dy)] - - mind = min(d) - - ind = d.index(mind) - - mind = math.sqrt(mind) - - dxl = cx[ind] - state.x - dyl = cy[ind] - state.y - - angle = pi_2_pi(cyaw[ind] - math.atan2(dyl, dxl)) - if angle < 0: - mind *= -1 - - return ind, mind - - -def closed_loop_prediction(cx, cy, cyaw, ck, speed_profile, goal): - T = 500.0 # max simulation time - goal_dis = 0.3 - stop_speed = 0.05 - - state = State(x=-0.0, y=-0.0, yaw=0.0, v=0.0) - - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - - e, e_th = 0.0, 0.0 - - while T >= time: - dl, target_ind, e, e_th = lqr_steering_control( - state, cx, cy, cyaw, ck, e, e_th) - - ai = pid_control(speed_profile[target_ind], state.v) - state = update(state, ai, dl) - - if abs(state.v) <= stop_speed: - target_ind += 1 - - time = time + dt - - # check goal - dx = state.x - goal[0] - dy = state.y - goal[1] - if math.hypot(dx, dy) <= goal_dis: - print("Goal") - break - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - - if target_ind % 1 == 0 and show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(cx, cy, "-r", label="course") - plt.plot(x, y, "ob", label="trajectory") - plt.plot(cx[target_ind], cy[target_ind], "xg", label="target") - plt.axis("equal") - plt.grid(True) - plt.title("speed[km/h]:" + str(round(state.v * 3.6, 2)) - + ",target index:" + str(target_ind)) - plt.pause(0.0001) - - return t, x, y, yaw, v - - -def calc_speed_profile(cx, cy, cyaw, target_speed): - speed_profile = [target_speed] * len(cx) - - direction = 1.0 - - # Set stop point - for i in range(len(cx) - 1): - dyaw = abs(cyaw[i + 1] - cyaw[i]) - switch = math.pi / 4.0 <= dyaw < math.pi / 2.0 - - if switch: - direction *= -1 - - if direction != 1.0: - speed_profile[i] = - target_speed - else: - speed_profile[i] = target_speed - - if switch: - speed_profile[i] = 0.0 - - speed_profile[-1] = 0.0 - - return speed_profile - - -def main(): - print("LQR steering control tracking start!!") - ax = [0.0, 6.0, 12.5, 10.0, 7.5, 3.0, -1.0] - ay = [0.0, -3.0, -5.0, 6.5, 3.0, 5.0, -2.0] - goal = [ax[-1], ay[-1]] - - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=0.1) - target_speed = 10.0 / 3.6 # simulation parameter km/h -> m/s - - sp = calc_speed_profile(cx, cy, cyaw, target_speed) - - t, x, y, yaw, v = closed_loop_prediction(cx, cy, cyaw, ck, sp, goal) - - if show_animation: # pragma: no cover - plt.close() - plt.subplots(1) - plt.plot(ax, ay, "xb", label="input") - plt.plot(cx, cy, "-r", label="spline") - plt.plot(x, y, "-g", label="tracking") - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - - plt.subplots(1) - plt.plot(s, [np.rad2deg(iyaw) for iyaw in cyaw], "-r", label="yaw") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("yaw angle[deg]") - - plt.subplots(1) - plt.plot(s, ck, "-r", label="curvature") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("curvature [1/m]") - - plt.show() - - -if __name__ == '__main__': - main() diff --git a/PathTracking/model_predictive_speed_and_steer_control/model_predictive_speed_and_steer_control.py b/PathTracking/model_predictive_speed_and_steer_control/model_predictive_speed_and_steer_control.py deleted file mode 100644 index eb2d7b6a738..00000000000 --- a/PathTracking/model_predictive_speed_and_steer_control/model_predictive_speed_and_steer_control.py +++ /dev/null @@ -1,628 +0,0 @@ -""" - -Path tracking simulation with iterative linear model predictive control for speed and steer control - -author: Atsushi Sakai (@Atsushi_twi) - -""" -import matplotlib.pyplot as plt -import time -import cvxpy -import math -import numpy as np -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -from utils.angle import angle_mod - -from PathPlanning.CubicSpline import cubic_spline_planner - -NX = 4 # x = x, y, v, yaw -NU = 2 # a = [accel, steer] -T = 5 # horizon length - -# mpc parameters -R = np.diag([0.01, 0.01]) # input cost matrix -Rd = np.diag([0.01, 1.0]) # input difference cost matrix -Q = np.diag([1.0, 1.0, 0.5, 0.5]) # state cost matrix -Qf = Q # state final matrix -GOAL_DIS = 1.5 # goal distance -STOP_SPEED = 0.5 / 3.6 # stop speed -MAX_TIME = 500.0 # max simulation time - -# iterative paramter -MAX_ITER = 3 # Max iteration -DU_TH = 0.1 # iteration finish param - -TARGET_SPEED = 10.0 / 3.6 # [m/s] target speed -N_IND_SEARCH = 10 # Search index number - -DT = 0.2 # [s] time tick - -# Vehicle parameters -LENGTH = 4.5 # [m] -WIDTH = 2.0 # [m] -BACKTOWHEEL = 1.0 # [m] -WHEEL_LEN = 0.3 # [m] -WHEEL_WIDTH = 0.2 # [m] -TREAD = 0.7 # [m] -WB = 2.5 # [m] - -MAX_STEER = np.deg2rad(45.0) # maximum steering angle [rad] -MAX_DSTEER = np.deg2rad(30.0) # maximum steering speed [rad/s] -MAX_SPEED = 55.0 / 3.6 # maximum speed [m/s] -MIN_SPEED = -20.0 / 3.6 # minimum speed [m/s] -MAX_ACCEL = 1.0 # maximum accel [m/ss] - -show_animation = True - - -class State: - """ - vehicle state class - """ - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - self.predelta = None - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def get_linear_model_matrix(v, phi, delta): - - A = np.zeros((NX, NX)) - A[0, 0] = 1.0 - A[1, 1] = 1.0 - A[2, 2] = 1.0 - A[3, 3] = 1.0 - A[0, 2] = DT * math.cos(phi) - A[0, 3] = - DT * v * math.sin(phi) - A[1, 2] = DT * math.sin(phi) - A[1, 3] = DT * v * math.cos(phi) - A[3, 2] = DT * math.tan(delta) / WB - - B = np.zeros((NX, NU)) - B[2, 0] = DT - B[3, 1] = DT * v / (WB * math.cos(delta) ** 2) - - C = np.zeros(NX) - C[0] = DT * v * math.sin(phi) * phi - C[1] = - DT * v * math.cos(phi) * phi - C[3] = - DT * v * delta / (WB * math.cos(delta) ** 2) - - return A, B, C - - -def plot_car(x, y, yaw, steer=0.0, cabcolor="-r", truckcolor="-k"): # pragma: no cover - - outline = np.array([[-BACKTOWHEEL, (LENGTH - BACKTOWHEEL), (LENGTH - BACKTOWHEEL), -BACKTOWHEEL, -BACKTOWHEEL], - [WIDTH / 2, WIDTH / 2, - WIDTH / 2, -WIDTH / 2, WIDTH / 2]]) - - fr_wheel = np.array([[WHEEL_LEN, -WHEEL_LEN, -WHEEL_LEN, WHEEL_LEN, WHEEL_LEN], - [-WHEEL_WIDTH - TREAD, -WHEEL_WIDTH - TREAD, WHEEL_WIDTH - TREAD, WHEEL_WIDTH - TREAD, -WHEEL_WIDTH - TREAD]]) - - rr_wheel = np.copy(fr_wheel) - - fl_wheel = np.copy(fr_wheel) - fl_wheel[1, :] *= -1 - rl_wheel = np.copy(rr_wheel) - rl_wheel[1, :] *= -1 - - Rot1 = np.array([[math.cos(yaw), math.sin(yaw)], - [-math.sin(yaw), math.cos(yaw)]]) - Rot2 = np.array([[math.cos(steer), math.sin(steer)], - [-math.sin(steer), math.cos(steer)]]) - - fr_wheel = (fr_wheel.T.dot(Rot2)).T - fl_wheel = (fl_wheel.T.dot(Rot2)).T - fr_wheel[0, :] += WB - fl_wheel[0, :] += WB - - fr_wheel = (fr_wheel.T.dot(Rot1)).T - fl_wheel = (fl_wheel.T.dot(Rot1)).T - - outline = (outline.T.dot(Rot1)).T - rr_wheel = (rr_wheel.T.dot(Rot1)).T - rl_wheel = (rl_wheel.T.dot(Rot1)).T - - outline[0, :] += x - outline[1, :] += y - fr_wheel[0, :] += x - fr_wheel[1, :] += y - rr_wheel[0, :] += x - rr_wheel[1, :] += y - fl_wheel[0, :] += x - fl_wheel[1, :] += y - rl_wheel[0, :] += x - rl_wheel[1, :] += y - - plt.plot(np.array(outline[0, :]).flatten(), - np.array(outline[1, :]).flatten(), truckcolor) - plt.plot(np.array(fr_wheel[0, :]).flatten(), - np.array(fr_wheel[1, :]).flatten(), truckcolor) - plt.plot(np.array(rr_wheel[0, :]).flatten(), - np.array(rr_wheel[1, :]).flatten(), truckcolor) - plt.plot(np.array(fl_wheel[0, :]).flatten(), - np.array(fl_wheel[1, :]).flatten(), truckcolor) - plt.plot(np.array(rl_wheel[0, :]).flatten(), - np.array(rl_wheel[1, :]).flatten(), truckcolor) - plt.plot(x, y, "*") - - -def update_state(state, a, delta): - - # input check - if delta >= MAX_STEER: - delta = MAX_STEER - elif delta <= -MAX_STEER: - delta = -MAX_STEER - - state.x = state.x + state.v * math.cos(state.yaw) * DT - state.y = state.y + state.v * math.sin(state.yaw) * DT - state.yaw = state.yaw + state.v / WB * math.tan(delta) * DT - state.v = state.v + a * DT - - if state.v > MAX_SPEED: - state.v = MAX_SPEED - elif state.v < MIN_SPEED: - state.v = MIN_SPEED - - return state - - -def get_nparray_from_matrix(x): - return np.array(x).flatten() - - -def calc_nearest_index(state, cx, cy, cyaw, pind): - - dx = [state.x - icx for icx in cx[pind:(pind + N_IND_SEARCH)]] - dy = [state.y - icy for icy in cy[pind:(pind + N_IND_SEARCH)]] - - d = [idx ** 2 + idy ** 2 for (idx, idy) in zip(dx, dy)] - - mind = min(d) - - ind = d.index(mind) + pind - - mind = math.sqrt(mind) - - dxl = cx[ind] - state.x - dyl = cy[ind] - state.y - - angle = pi_2_pi(cyaw[ind] - math.atan2(dyl, dxl)) - if angle < 0: - mind *= -1 - - return ind, mind - - -def predict_motion(x0, oa, od, xref): - xbar = xref * 0.0 - for i, _ in enumerate(x0): - xbar[i, 0] = x0[i] - - state = State(x=x0[0], y=x0[1], yaw=x0[3], v=x0[2]) - for (ai, di, i) in zip(oa, od, range(1, T + 1)): - state = update_state(state, ai, di) - xbar[0, i] = state.x - xbar[1, i] = state.y - xbar[2, i] = state.v - xbar[3, i] = state.yaw - - return xbar - - -def iterative_linear_mpc_control(xref, x0, dref, oa, od): - """ - MPC control with updating operational point iteratively - """ - ox, oy, oyaw, ov = None, None, None, None - - if oa is None or od is None: - oa = [0.0] * T - od = [0.0] * T - - for i in range(MAX_ITER): - xbar = predict_motion(x0, oa, od, xref) - poa, pod = oa[:], od[:] - oa, od, ox, oy, oyaw, ov = linear_mpc_control(xref, xbar, x0, dref) - du = sum(abs(oa - poa)) + sum(abs(od - pod)) # calc u change value - if du <= DU_TH: - break - else: - print("Iterative is max iter") - - return oa, od, ox, oy, oyaw, ov - - -def linear_mpc_control(xref, xbar, x0, dref): - """ - linear mpc control - - xref: reference point - xbar: operational point - x0: initial state - dref: reference steer angle - """ - - x = cvxpy.Variable((NX, T + 1)) - u = cvxpy.Variable((NU, T)) - - cost = 0.0 - constraints = [] - - for t in range(T): - cost += cvxpy.quad_form(u[:, t], R) - - if t != 0: - cost += cvxpy.quad_form(xref[:, t] - x[:, t], Q) - - A, B, C = get_linear_model_matrix( - xbar[2, t], xbar[3, t], dref[0, t]) - constraints += [x[:, t + 1] == A @ x[:, t] + B @ u[:, t] + C] - - if t < (T - 1): - cost += cvxpy.quad_form(u[:, t + 1] - u[:, t], Rd) - constraints += [cvxpy.abs(u[1, t + 1] - u[1, t]) <= - MAX_DSTEER * DT] - - cost += cvxpy.quad_form(xref[:, T] - x[:, T], Qf) - - constraints += [x[:, 0] == x0] - constraints += [x[2, :] <= MAX_SPEED] - constraints += [x[2, :] >= MIN_SPEED] - constraints += [cvxpy.abs(u[0, :]) <= MAX_ACCEL] - constraints += [cvxpy.abs(u[1, :]) <= MAX_STEER] - - prob = cvxpy.Problem(cvxpy.Minimize(cost), constraints) - prob.solve(solver=cvxpy.CLARABEL, verbose=False) - - if prob.status == cvxpy.OPTIMAL or prob.status == cvxpy.OPTIMAL_INACCURATE: - ox = get_nparray_from_matrix(x.value[0, :]) - oy = get_nparray_from_matrix(x.value[1, :]) - ov = get_nparray_from_matrix(x.value[2, :]) - oyaw = get_nparray_from_matrix(x.value[3, :]) - oa = get_nparray_from_matrix(u.value[0, :]) - odelta = get_nparray_from_matrix(u.value[1, :]) - - else: - print("Error: Cannot solve mpc..") - oa, odelta, ox, oy, oyaw, ov = None, None, None, None, None, None - - return oa, odelta, ox, oy, oyaw, ov - - -def calc_ref_trajectory(state, cx, cy, cyaw, ck, sp, dl, pind): - xref = np.zeros((NX, T + 1)) - dref = np.zeros((1, T + 1)) - ncourse = len(cx) - - ind, _ = calc_nearest_index(state, cx, cy, cyaw, pind) - - if pind >= ind: - ind = pind - - xref[0, 0] = cx[ind] - xref[1, 0] = cy[ind] - xref[2, 0] = sp[ind] - xref[3, 0] = cyaw[ind] - dref[0, 0] = 0.0 # steer operational point should be 0 - - travel = 0.0 - - for i in range(T + 1): - travel += abs(state.v) * DT - dind = int(round(travel / dl)) - - if (ind + dind) < ncourse: - xref[0, i] = cx[ind + dind] - xref[1, i] = cy[ind + dind] - xref[2, i] = sp[ind + dind] - xref[3, i] = cyaw[ind + dind] - dref[0, i] = 0.0 - else: - xref[0, i] = cx[ncourse - 1] - xref[1, i] = cy[ncourse - 1] - xref[2, i] = sp[ncourse - 1] - xref[3, i] = cyaw[ncourse - 1] - dref[0, i] = 0.0 - - return xref, ind, dref - - -def check_goal(state, goal, tind, nind): - - # check goal - dx = state.x - goal[0] - dy = state.y - goal[1] - d = math.hypot(dx, dy) - - isgoal = (d <= GOAL_DIS) - - if abs(tind - nind) >= 5: - isgoal = False - - isstop = (abs(state.v) <= STOP_SPEED) - - if isgoal and isstop: - return True - - return False - - -def do_simulation(cx, cy, cyaw, ck, sp, dl, initial_state): - """ - Simulation - - cx: course x position list - cy: course y position list - cy: course yaw position list - ck: course curvature list - sp: speed profile - dl: course tick [m] - - """ - - goal = [cx[-1], cy[-1]] - - state = initial_state - - # initial yaw compensation - if state.yaw - cyaw[0] >= math.pi: - state.yaw -= math.pi * 2.0 - elif state.yaw - cyaw[0] <= -math.pi: - state.yaw += math.pi * 2.0 - - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - d = [0.0] - a = [0.0] - target_ind, _ = calc_nearest_index(state, cx, cy, cyaw, 0) - - odelta, oa = None, None - - cyaw = smooth_yaw(cyaw) - - while MAX_TIME >= time: - xref, target_ind, dref = calc_ref_trajectory( - state, cx, cy, cyaw, ck, sp, dl, target_ind) - - x0 = [state.x, state.y, state.v, state.yaw] # current state - - oa, odelta, ox, oy, oyaw, ov = iterative_linear_mpc_control( - xref, x0, dref, oa, odelta) - - di, ai = 0.0, 0.0 - if odelta is not None: - di, ai = odelta[0], oa[0] - state = update_state(state, ai, di) - - time = time + DT - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - d.append(di) - a.append(ai) - - if check_goal(state, goal, target_ind, len(cx)): - print("Goal") - break - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if ox is not None: - plt.plot(ox, oy, "xr", label="MPC") - plt.plot(cx, cy, "-r", label="course") - plt.plot(x, y, "ob", label="trajectory") - plt.plot(xref[0, :], xref[1, :], "xk", label="xref") - plt.plot(cx[target_ind], cy[target_ind], "xg", label="target") - plot_car(state.x, state.y, state.yaw, steer=di) - plt.axis("equal") - plt.grid(True) - plt.title("Time[s]:" + str(round(time, 2)) - + ", speed[km/h]:" + str(round(state.v * 3.6, 2))) - plt.pause(0.0001) - - return t, x, y, yaw, v, d, a - - -def calc_speed_profile(cx, cy, cyaw, target_speed): - - speed_profile = [target_speed] * len(cx) - direction = 1.0 # forward - - # Set stop point - for i in range(len(cx) - 1): - dx = cx[i + 1] - cx[i] - dy = cy[i + 1] - cy[i] - - move_direction = math.atan2(dy, dx) - - if dx != 0.0 and dy != 0.0: - dangle = abs(pi_2_pi(move_direction - cyaw[i])) - if dangle >= math.pi / 4.0: - direction = -1.0 - else: - direction = 1.0 - - if direction != 1.0: - speed_profile[i] = - target_speed - else: - speed_profile[i] = target_speed - - speed_profile[-1] = 0.0 - - return speed_profile - - -def smooth_yaw(yaw): - - for i in range(len(yaw) - 1): - dyaw = yaw[i + 1] - yaw[i] - - while dyaw >= math.pi / 2.0: - yaw[i + 1] -= math.pi * 2.0 - dyaw = yaw[i + 1] - yaw[i] - - while dyaw <= -math.pi / 2.0: - yaw[i + 1] += math.pi * 2.0 - dyaw = yaw[i + 1] - yaw[i] - - return yaw - - -def get_straight_course(dl): - ax = [0.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0] - ay = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=dl) - - return cx, cy, cyaw, ck - - -def get_straight_course2(dl): - ax = [0.0, -10.0, -20.0, -40.0, -50.0, -60.0, -70.0] - ay = [0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0] - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=dl) - - return cx, cy, cyaw, ck - - -def get_straight_course3(dl): - ax = [0.0, -10.0, -20.0, -40.0, -50.0, -60.0, -70.0] - ay = [0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0] - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=dl) - - cyaw = [i - math.pi for i in cyaw] - - return cx, cy, cyaw, ck - - -def get_forward_course(dl): - ax = [0.0, 60.0, 125.0, 50.0, 75.0, 30.0, -10.0] - ay = [0.0, 0.0, 50.0, 65.0, 30.0, 50.0, -20.0] - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=dl) - - return cx, cy, cyaw, ck - - -def get_switch_back_course(dl): - ax = [0.0, 30.0, 6.0, 20.0, 35.0] - ay = [0.0, 0.0, 20.0, 35.0, 20.0] - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=dl) - ax = [35.0, 10.0, 0.0, 0.0] - ay = [20.0, 30.0, 5.0, 0.0] - cx2, cy2, cyaw2, ck2, s2 = cubic_spline_planner.calc_spline_course( - ax, ay, ds=dl) - cyaw2 = [i - math.pi for i in cyaw2] - cx.extend(cx2) - cy.extend(cy2) - cyaw.extend(cyaw2) - ck.extend(ck2) - - return cx, cy, cyaw, ck - - -def main(): - print(__file__ + " start!!") - start = time.time() - - dl = 1.0 # course tick - # cx, cy, cyaw, ck = get_straight_course(dl) - # cx, cy, cyaw, ck = get_straight_course2(dl) - # cx, cy, cyaw, ck = get_straight_course3(dl) - # cx, cy, cyaw, ck = get_forward_course(dl) - cx, cy, cyaw, ck = get_switch_back_course(dl) - - sp = calc_speed_profile(cx, cy, cyaw, TARGET_SPEED) - - initial_state = State(x=cx[0], y=cy[0], yaw=cyaw[0], v=0.0) - - t, x, y, yaw, v, d, a = do_simulation( - cx, cy, cyaw, ck, sp, dl, initial_state) - - elapsed_time = time.time() - start - print(f"calc time:{elapsed_time:.6f} [sec]") - - if show_animation: # pragma: no cover - plt.close("all") - plt.subplots() - plt.plot(cx, cy, "-r", label="spline") - plt.plot(x, y, "-g", label="tracking") - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - - plt.subplots() - plt.plot(t, v, "-r", label="speed") - plt.grid(True) - plt.xlabel("Time [s]") - plt.ylabel("Speed [kmh]") - - plt.show() - - -def main2(): - print(__file__ + " start!!") - start = time.time() - - dl = 1.0 # course tick - cx, cy, cyaw, ck = get_straight_course3(dl) - - sp = calc_speed_profile(cx, cy, cyaw, TARGET_SPEED) - - initial_state = State(x=cx[0], y=cy[0], yaw=0.0, v=0.0) - - t, x, y, yaw, v, d, a = do_simulation( - cx, cy, cyaw, ck, sp, dl, initial_state) - - elapsed_time = time.time() - start - print(f"calc time:{elapsed_time:.6f} [sec]") - - if show_animation: # pragma: no cover - plt.close("all") - plt.subplots() - plt.plot(cx, cy, "-r", label="spline") - plt.plot(x, y, "-g", label="tracking") - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - - plt.subplots() - plt.plot(t, v, "-r", label="speed") - plt.grid(True) - plt.xlabel("Time [s]") - plt.ylabel("Speed [kmh]") - - plt.show() - - -if __name__ == '__main__': - main() - # main2() diff --git a/PathTracking/move_to_pose/__init__.py b/PathTracking/move_to_pose/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/PathTracking/move_to_pose/move_to_pose.py b/PathTracking/move_to_pose/move_to_pose.py deleted file mode 100644 index 34736a2e213..00000000000 --- a/PathTracking/move_to_pose/move_to_pose.py +++ /dev/null @@ -1,223 +0,0 @@ -""" - -Move to specified pose - -Author: Daniel Ingram (daniel-s-ingram) - Atsushi Sakai (@Atsushi_twi) - Seied Muhammad Yazdian (@Muhammad-Yazdian) - Wang Zheng (@Aglargil) - -P. I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7 - -""" - -import matplotlib.pyplot as plt -import numpy as np -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) -from utils.angle import angle_mod -from random import random - - -class PathFinderController: - """ - Constructs an instantiate of the PathFinderController for navigating a - 3-DOF wheeled robot on a 2D plane - - Parameters - ---------- - Kp_rho : The linear velocity gain to translate the robot along a line - towards the goal - Kp_alpha : The angular velocity gain to rotate the robot towards the goal - Kp_beta : The offset angular velocity gain accounting for smooth merging to - the goal angle (i.e., it helps the robot heading to be parallel - to the target angle.) - """ - - def __init__(self, Kp_rho, Kp_alpha, Kp_beta): - self.Kp_rho = Kp_rho - self.Kp_alpha = Kp_alpha - self.Kp_beta = Kp_beta - - def calc_control_command(self, x_diff, y_diff, theta, theta_goal): - """ - Returns the control command for the linear and angular velocities as - well as the distance to goal - - Parameters - ---------- - x_diff : The position of target with respect to current robot position - in x direction - y_diff : The position of target with respect to current robot position - in y direction - theta : The current heading angle of robot with respect to x axis - theta_goal: The target angle of robot with respect to x axis - - Returns - ------- - rho : The distance between the robot and the goal position - v : Command linear velocity - w : Command angular velocity - """ - - # Description of local variables: - # - alpha is the angle to the goal relative to the heading of the robot - # - beta is the angle between the robot's position and the goal - # position plus the goal angle - # - Kp_rho*rho and Kp_alpha*alpha drive the robot along a line towards - # the goal - # - Kp_beta*beta rotates the line so that it is parallel to the goal - # angle - # - # Note: - # we restrict alpha and beta (angle differences) to the range - # [-pi, pi] to prevent unstable behavior e.g. difference going - # from 0 rad to 2*pi rad with slight turn - - # Ref: The velocity v always has a constant sign which depends on the initial value of α. - rho = np.hypot(x_diff, y_diff) - v = self.Kp_rho * rho - - alpha = angle_mod(np.arctan2(y_diff, x_diff) - theta) - beta = angle_mod(theta_goal - theta - alpha) - if alpha > np.pi / 2 or alpha < -np.pi / 2: - # recalculate alpha to make alpha in the range of [-pi/2, pi/2] - alpha = angle_mod(np.arctan2(-y_diff, -x_diff) - theta) - beta = angle_mod(theta_goal - theta - alpha) - w = self.Kp_alpha * alpha - self.Kp_beta * beta - v = -v - else: - w = self.Kp_alpha * alpha - self.Kp_beta * beta - - return rho, v, w - - -# simulation parameters -controller = PathFinderController(9, 15, 3) -dt = 0.01 -MAX_SIM_TIME = 5 # seconds, robot will stop moving when time exceeds this value - -# Robot specifications -MAX_LINEAR_SPEED = 15 -MAX_ANGULAR_SPEED = 7 - -show_animation = True - - -def move_to_pose(x_start, y_start, theta_start, x_goal, y_goal, theta_goal): - x = x_start - y = y_start - theta = theta_start - - x_diff = x_goal - x - y_diff = y_goal - y - - x_traj, y_traj, v_traj, w_traj = [x], [y], [0], [0] - - rho = np.hypot(x_diff, y_diff) - t = 0 - while rho > 0.001 and t < MAX_SIM_TIME: - t += dt - x_traj.append(x) - y_traj.append(y) - - x_diff = x_goal - x - y_diff = y_goal - y - - rho, v, w = controller.calc_control_command(x_diff, y_diff, theta, theta_goal) - - if abs(v) > MAX_LINEAR_SPEED: - v = np.sign(v) * MAX_LINEAR_SPEED - - if abs(w) > MAX_ANGULAR_SPEED: - w = np.sign(w) * MAX_ANGULAR_SPEED - - v_traj.append(v) - w_traj.append(w) - - theta = theta + w * dt - x = x + v * np.cos(theta) * dt - y = y + v * np.sin(theta) * dt - - if show_animation: # pragma: no cover - plt.cla() - plt.arrow( - x_start, - y_start, - np.cos(theta_start), - np.sin(theta_start), - color="r", - width=0.1, - ) - plt.arrow( - x_goal, - y_goal, - np.cos(theta_goal), - np.sin(theta_goal), - color="g", - width=0.1, - ) - plot_vehicle(x, y, theta, x_traj, y_traj) - - return x_traj, y_traj, v_traj, w_traj - - -def plot_vehicle(x, y, theta, x_traj, y_traj): # pragma: no cover - # Corners of triangular vehicle when pointing to the right (0 radians) - p1_i = np.array([0.5, 0, 1]).T - p2_i = np.array([-0.5, 0.25, 1]).T - p3_i = np.array([-0.5, -0.25, 1]).T - - T = transformation_matrix(x, y, theta) - p1 = np.matmul(T, p1_i) - p2 = np.matmul(T, p2_i) - p3 = np.matmul(T, p3_i) - - plt.plot([p1[0], p2[0]], [p1[1], p2[1]], "k-") - plt.plot([p2[0], p3[0]], [p2[1], p3[1]], "k-") - plt.plot([p3[0], p1[0]], [p3[1], p1[1]], "k-") - - plt.plot(x_traj, y_traj, "b--") - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - "key_release_event", lambda event: [exit(0) if event.key == "escape" else None] - ) - - plt.xlim(0, 20) - plt.ylim(0, 20) - - plt.pause(dt) - - -def transformation_matrix(x, y, theta): - return np.array( - [ - [np.cos(theta), -np.sin(theta), x], - [np.sin(theta), np.cos(theta), y], - [0, 0, 1], - ] - ) - - -def main(): - for i in range(5): - x_start = 20.0 * random() - y_start = 20.0 * random() - theta_start: float = 2 * np.pi * random() - np.pi - x_goal = 20 * random() - y_goal = 20 * random() - theta_goal = 2 * np.pi * random() - np.pi - print( - f"Initial x: {round(x_start, 2)} m\nInitial y: {round(y_start, 2)} m\nInitial theta: {round(theta_start, 2)} rad\n" - ) - print( - f"Goal x: {round(x_goal, 2)} m\nGoal y: {round(y_goal, 2)} m\nGoal theta: {round(theta_goal, 2)} rad\n" - ) - move_to_pose(x_start, y_start, theta_start, x_goal, y_goal, theta_goal) - - -if __name__ == "__main__": - main() diff --git a/PathTracking/move_to_pose/move_to_pose_robot.py b/PathTracking/move_to_pose/move_to_pose_robot.py deleted file mode 100644 index fe9f0d06b35..00000000000 --- a/PathTracking/move_to_pose/move_to_pose_robot.py +++ /dev/null @@ -1,240 +0,0 @@ -""" - -Move to specified pose (with Robot class) - -Author: Daniel Ingram (daniel-s-ingram) - Atsushi Sakai (@Atsushi_twi) - Seied Muhammad Yazdian (@Muhammad-Yazdian) - -P.I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7 - -""" - -import matplotlib.pyplot as plt -import numpy as np -import copy -from move_to_pose import PathFinderController - -# Simulation parameters -TIME_DURATION = 1000 -TIME_STEP = 0.01 -AT_TARGET_ACCEPTANCE_THRESHOLD = 0.01 -SHOW_ANIMATION = True -PLOT_WINDOW_SIZE_X = 20 -PLOT_WINDOW_SIZE_Y = 20 -PLOT_FONT_SIZE = 8 - -simulation_running = True -all_robots_are_at_target = False - - -class Pose: - """2D pose""" - - def __init__(self, x, y, theta): - self.x = x - self.y = y - self.theta = theta - - -class Robot: - """ - Constructs an instantiate of the 3-DOF wheeled Robot navigating on a - 2D plane - - Parameters - ---------- - name : (string) - The name of the robot - color : (string) - The color of the robot - max_linear_speed : (float) - The maximum linear speed that the robot can go - max_angular_speed : (float) - The maximum angular speed that the robot can rotate about its vertical - axis - path_finder_controller : (PathFinderController) - A configurable controller to finds the path and calculates command - linear and angular velocities. - """ - - def __init__(self, name, color, max_linear_speed, max_angular_speed, - path_finder_controller): - self.name = name - self.color = color - self.MAX_LINEAR_SPEED = max_linear_speed - self.MAX_ANGULAR_SPEED = max_angular_speed - self.path_finder_controller = path_finder_controller - self.x_traj = [] - self.y_traj = [] - self.pose = Pose(0, 0, 0) - self.pose_start = Pose(0, 0, 0) - self.pose_target = Pose(0, 0, 0) - self.is_at_target = False - - def set_start_target_poses(self, pose_start, pose_target): - """ - Sets the start and target positions of the robot - - Parameters - ---------- - pose_start : (Pose) - Start position of the robot (see the Pose class) - pose_target : (Pose) - Target position of the robot (see the Pose class) - """ - self.pose_start = copy.copy(pose_start) - self.pose_target = pose_target - self.pose = pose_start - - def move(self, dt): - """ - Moves the robot for one time step increment - - Parameters - ---------- - dt : (float) - time step - """ - self.x_traj.append(self.pose.x) - self.y_traj.append(self.pose.y) - - rho, linear_velocity, angular_velocity = \ - self.path_finder_controller.calc_control_command( - self.pose_target.x - self.pose.x, - self.pose_target.y - self.pose.y, - self.pose.theta, self.pose_target.theta) - - if rho < AT_TARGET_ACCEPTANCE_THRESHOLD: - self.is_at_target = True - - if abs(linear_velocity) > self.MAX_LINEAR_SPEED: - linear_velocity = (np.sign(linear_velocity) - * self.MAX_LINEAR_SPEED) - - if abs(angular_velocity) > self.MAX_ANGULAR_SPEED: - angular_velocity = (np.sign(angular_velocity) - * self.MAX_ANGULAR_SPEED) - - self.pose.theta = self.pose.theta + angular_velocity * dt - self.pose.x = self.pose.x + linear_velocity * \ - np.cos(self.pose.theta) * dt - self.pose.y = self.pose.y + linear_velocity * \ - np.sin(self.pose.theta) * dt - - -def run_simulation(robots): - """Simulates all robots simultaneously""" - global all_robots_are_at_target - global simulation_running - - robot_names = [] - for instance in robots: - robot_names.append(instance.name) - - time = 0 - while simulation_running and time < TIME_DURATION: - time += TIME_STEP - robots_are_at_target = [] - - for instance in robots: - if not instance.is_at_target: - instance.move(TIME_STEP) - robots_are_at_target.append(instance.is_at_target) - - if all(robots_are_at_target): - simulation_running = False - - if SHOW_ANIMATION: - plt.cla() - plt.xlim(0, PLOT_WINDOW_SIZE_X) - plt.ylim(0, PLOT_WINDOW_SIZE_Y) - - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - plt.text(0.3, PLOT_WINDOW_SIZE_Y - 1, - 'Time: {:.2f}'.format(time), - fontsize=PLOT_FONT_SIZE) - - plt.text(0.3, PLOT_WINDOW_SIZE_Y - 2, - 'Reached target: {} = '.format(robot_names) - + str(robots_are_at_target), - fontsize=PLOT_FONT_SIZE) - - for instance in robots: - plt.arrow(instance.pose_start.x, - instance.pose_start.y, - np.cos(instance.pose_start.theta), - np.sin(instance.pose_start.theta), - color='r', - width=0.1) - plt.arrow(instance.pose_target.x, - instance.pose_target.y, - np.cos(instance.pose_target.theta), - np.sin(instance.pose_target.theta), - color='g', - width=0.1) - plot_vehicle(instance.pose.x, - instance.pose.y, - instance.pose.theta, - instance.x_traj, - instance.y_traj, instance.color) - - plt.pause(TIME_STEP) - - -def plot_vehicle(x, y, theta, x_traj, y_traj, color): - # Corners of triangular vehicle when pointing to the right (0 radians) - p1_i = np.array([0.5, 0, 1]).T - p2_i = np.array([-0.5, 0.25, 1]).T - p3_i = np.array([-0.5, -0.25, 1]).T - - T = transformation_matrix(x, y, theta) - p1 = T @ p1_i - p2 = T @ p2_i - p3 = T @ p3_i - - plt.plot([p1[0], p2[0]], [p1[1], p2[1]], color+'-') - plt.plot([p2[0], p3[0]], [p2[1], p3[1]], color+'-') - plt.plot([p3[0], p1[0]], [p3[1], p1[1]], color+'-') - - plt.plot(x_traj, y_traj, color+'--') - - -def transformation_matrix(x, y, theta): - return np.array([ - [np.cos(theta), -np.sin(theta), x], - [np.sin(theta), np.cos(theta), y], - [0, 0, 1] - ]) - - -def main(): - pose_target = Pose(15, 15, -1) - - pose_start_1 = Pose(5, 2, 0) - pose_start_2 = Pose(5, 2, 0) - pose_start_3 = Pose(5, 2, 0) - - controller_1 = PathFinderController(5, 8, 2) - controller_2 = PathFinderController(5, 16, 4) - controller_3 = PathFinderController(10, 25, 6) - - robot_1 = Robot("Yellow Robot", "y", 12, 5, controller_1) - robot_2 = Robot("Black Robot", "k", 16, 5, controller_2) - robot_3 = Robot("Blue Robot", "b", 20, 5, controller_3) - - robot_1.set_start_target_poses(pose_start_1, pose_target) - robot_2.set_start_target_poses(pose_start_2, pose_target) - robot_3.set_start_target_poses(pose_start_3, pose_target) - - robots: list[Robot] = [robot_1, robot_2, robot_3] - - run_simulation(robots) - - -if __name__ == '__main__': - main() diff --git a/PathTracking/pure_pursuit/pure_pursuit.py b/PathTracking/pure_pursuit/pure_pursuit.py deleted file mode 100644 index ff995033a9e..00000000000 --- a/PathTracking/pure_pursuit/pure_pursuit.py +++ /dev/null @@ -1,215 +0,0 @@ -""" - -Path tracking simulation with pure pursuit steering and PID speed control. - -author: Atsushi Sakai (@Atsushi_twi) - Guillaume Jacquenot (@Gjacquenot) - -""" -import numpy as np -import math -import matplotlib.pyplot as plt - -# Parameters -k = 0.1 # look forward gain -Lfc = 2.0 # [m] look-ahead distance -Kp = 1.0 # speed proportional gain -dt = 0.1 # [s] time tick -WB = 2.9 # [m] wheel base of vehicle - -show_animation = True - - -class State: - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - self.rear_x = self.x - ((WB / 2) * math.cos(self.yaw)) - self.rear_y = self.y - ((WB / 2) * math.sin(self.yaw)) - - def update(self, a, delta): - self.x += self.v * math.cos(self.yaw) * dt - self.y += self.v * math.sin(self.yaw) * dt - self.yaw += self.v / WB * math.tan(delta) * dt - self.v += a * dt - self.rear_x = self.x - ((WB / 2) * math.cos(self.yaw)) - self.rear_y = self.y - ((WB / 2) * math.sin(self.yaw)) - - def calc_distance(self, point_x, point_y): - dx = self.rear_x - point_x - dy = self.rear_y - point_y - return math.hypot(dx, dy) - - -class States: - - def __init__(self): - self.x = [] - self.y = [] - self.yaw = [] - self.v = [] - self.t = [] - - def append(self, t, state): - self.x.append(state.x) - self.y.append(state.y) - self.yaw.append(state.yaw) - self.v.append(state.v) - self.t.append(t) - - -def proportional_control(target, current): - a = Kp * (target - current) - - return a - - -class TargetCourse: - - def __init__(self, cx, cy): - self.cx = cx - self.cy = cy - self.old_nearest_point_index = None - - def search_target_index(self, state): - - # To speed up nearest point search, doing it at only first time. - if self.old_nearest_point_index is None: - # search nearest point index - dx = [state.rear_x - icx for icx in self.cx] - dy = [state.rear_y - icy for icy in self.cy] - d = np.hypot(dx, dy) - ind = np.argmin(d) - self.old_nearest_point_index = ind - else: - ind = self.old_nearest_point_index - distance_this_index = state.calc_distance(self.cx[ind], - self.cy[ind]) - while True: - distance_next_index = state.calc_distance(self.cx[ind + 1], - self.cy[ind + 1]) - if distance_this_index < distance_next_index: - break - ind = ind + 1 if (ind + 1) < len(self.cx) else ind - distance_this_index = distance_next_index - self.old_nearest_point_index = ind - - Lf = k * state.v + Lfc # update look ahead distance - - # search look ahead target point index - while Lf > state.calc_distance(self.cx[ind], self.cy[ind]): - if (ind + 1) >= len(self.cx): - break # not exceed goal - ind += 1 - - return ind, Lf - - -def pure_pursuit_steer_control(state, trajectory, pind): - ind, Lf = trajectory.search_target_index(state) - - if pind >= ind: - ind = pind - - if ind < len(trajectory.cx): - tx = trajectory.cx[ind] - ty = trajectory.cy[ind] - else: # toward goal - tx = trajectory.cx[-1] - ty = trajectory.cy[-1] - ind = len(trajectory.cx) - 1 - - alpha = math.atan2(ty - state.rear_y, tx - state.rear_x) - state.yaw - - delta = math.atan2(2.0 * WB * math.sin(alpha) / Lf, 1.0) - - return delta, ind - - -def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"): - """ - Plot arrow - """ - - if not isinstance(x, float): - for ix, iy, iyaw in zip(x, y, yaw): - plot_arrow(ix, iy, iyaw) - else: - plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw), - fc=fc, ec=ec, head_width=width, head_length=width) - plt.plot(x, y) - - -def main(): - # target course - cx = np.arange(0, 50, 0.5) - cy = [math.sin(ix / 5.0) * ix / 2.0 for ix in cx] - - target_speed = 10.0 / 3.6 # [m/s] - - T = 100.0 # max simulation time - - # initial state - state = State(x=-0.0, y=-3.0, yaw=0.0, v=0.0) - - lastIndex = len(cx) - 1 - time = 0.0 - states = States() - states.append(time, state) - target_course = TargetCourse(cx, cy) - target_ind, _ = target_course.search_target_index(state) - - while T >= time and lastIndex > target_ind: - - # Calc control input - ai = proportional_control(target_speed, state.v) - di, target_ind = pure_pursuit_steer_control( - state, target_course, target_ind) - - state.update(ai, di) # Control vehicle - - time += dt - states.append(time, state) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plot_arrow(state.x, state.y, state.yaw) - plt.plot(cx, cy, "-r", label="course") - plt.plot(states.x, states.y, "-b", label="trajectory") - plt.plot(cx[target_ind], cy[target_ind], "xg", label="target") - plt.axis("equal") - plt.grid(True) - plt.title("Speed[km/h]:" + str(state.v * 3.6)[:4]) - plt.pause(0.001) - - # Test - assert lastIndex >= target_ind, "Cannot goal" - - if show_animation: # pragma: no cover - plt.cla() - plt.plot(cx, cy, ".r", label="course") - plt.plot(states.x, states.y, "-b", label="trajectory") - plt.legend() - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.axis("equal") - plt.grid(True) - - plt.subplots(1) - plt.plot(states.t, [iv * 3.6 for iv in states.v], "-r") - plt.xlabel("Time[s]") - plt.ylabel("Speed[km/h]") - plt.grid(True) - plt.show() - - -if __name__ == '__main__': - print("Pure pursuit path tracking simulation start") - main() diff --git a/PathTracking/rear_wheel_feedback/rear_wheel_feedback.py b/PathTracking/rear_wheel_feedback/rear_wheel_feedback.py deleted file mode 100644 index fd04fb6d171..00000000000 --- a/PathTracking/rear_wheel_feedback/rear_wheel_feedback.py +++ /dev/null @@ -1,234 +0,0 @@ -""" - -Path tracking simulation with rear wheel feedback steering control and PID speed control. - -author: Atsushi Sakai(@Atsushi_twi) - -""" -import matplotlib.pyplot as plt -import math -import numpy as np -import sys -import pathlib -from scipy import interpolate -from scipy import optimize - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) -from utils.angle import angle_mod - -Kp = 1.0 # speed proportional gain -# steering control parameter -KTH = 1.0 -KE = 0.5 - -dt = 0.1 # [s] -L = 2.9 # [m] - -show_animation = True - -class State: - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0, direction=1): - self.x = x - self.y = y - self.yaw = yaw - self.v = v - self.direction = direction - - def update(self, a, delta, dt): - self.x = self.x + self.v * math.cos(self.yaw) * dt - self.y = self.y + self.v * math.sin(self.yaw) * dt - self.yaw = self.yaw + self.v / L * math.tan(delta) * dt - self.v = self.v + a * dt - -class CubicSplinePath: - def __init__(self, x, y): - x, y = map(np.asarray, (x, y)) - s = np.append([0],(np.cumsum(np.diff(x)**2) + np.cumsum(np.diff(y)**2))**0.5) - - self.X = interpolate.CubicSpline(s, x) - self.Y = interpolate.CubicSpline(s, y) - - self.dX = self.X.derivative(1) - self.ddX = self.X.derivative(2) - - self.dY = self.Y.derivative(1) - self.ddY = self.Y.derivative(2) - - self.length = s[-1] - - def calc_yaw(self, s): - dx, dy = self.dX(s), self.dY(s) - return np.arctan2(dy, dx) - - def calc_curvature(self, s): - dx, dy = self.dX(s), self.dY(s) - ddx, ddy = self.ddX(s), self.ddY(s) - return (ddy * dx - ddx * dy) / ((dx ** 2 + dy ** 2)**(3 / 2)) - - def __find_nearest_point(self, s0, x, y): - def calc_distance(_s, *args): - _x, _y= self.X(_s), self.Y(_s) - return (_x - args[0])**2 + (_y - args[1])**2 - - def calc_distance_jacobian(_s, *args): - _x, _y = self.X(_s), self.Y(_s) - _dx, _dy = self.dX(_s), self.dY(_s) - return 2*_dx*(_x - args[0])+2*_dy*(_y-args[1]) - - minimum = optimize.fmin_cg(calc_distance, s0, calc_distance_jacobian, args=(x, y), full_output=True, disp=False) - return minimum - - def calc_track_error(self, x, y, s0): - ret = self.__find_nearest_point(s0, x, y) - - s = ret[0][0] - e = ret[1] - - k = self.calc_curvature(s) - yaw = self.calc_yaw(s) - - dxl = self.X(s) - x - dyl = self.Y(s) - y - angle = pi_2_pi(yaw - math.atan2(dyl, dxl)) - if angle < 0: - e*= -1 - - return e, k, yaw, s - -def pid_control(target, current): - a = Kp * (target - current) - return a - -def pi_2_pi(angle): - return angle_mod(angle) - -def rear_wheel_feedback_control(state, e, k, yaw_ref): - v = state.v - th_e = pi_2_pi(state.yaw - yaw_ref) - - omega = v * k * math.cos(th_e) / (1.0 - k * e) - \ - KTH * abs(v) * th_e - KE * v * math.sin(th_e) * e / th_e - - if th_e == 0.0 or omega == 0.0: - return 0.0 - - delta = math.atan2(L * omega / v, 1.0) - - return delta - - -def simulate(path_ref, goal): - T = 500.0 # max simulation time - goal_dis = 0.3 - - state = State(x=-0.0, y=-0.0, yaw=0.0, v=0.0) - - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - goal_flag = False - - s = np.arange(0, path_ref.length, 0.1) - e, k, yaw_ref, s0 = path_ref.calc_track_error(state.x, state.y, 0.0) - - while T >= time: - e, k, yaw_ref, s0 = path_ref.calc_track_error(state.x, state.y, s0) - di = rear_wheel_feedback_control(state, e, k, yaw_ref) - - speed_ref = calc_target_speed(state, yaw_ref) - ai = pid_control(speed_ref, state.v) - state.update(ai, di, dt) - - time = time + dt - - # check goal - dx = state.x - goal[0] - dy = state.y - goal[1] - if math.hypot(dx, dy) <= goal_dis: - print("Goal") - goal_flag = True - break - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - - if show_animation: - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(path_ref.X(s), path_ref.Y(s), "-r", label="course") - plt.plot(x, y, "ob", label="trajectory") - plt.plot(path_ref.X(s0), path_ref.Y(s0), "xg", label="target") - plt.axis("equal") - plt.grid(True) - plt.title(f"speed[km/h]:{round(state.v * 3.6, 2):.2f}, target s-param:{s0:.2f}") - plt.pause(0.0001) - - return t, x, y, yaw, v, goal_flag - -def calc_target_speed(state, yaw_ref): - target_speed = 10.0 / 3.6 - - dyaw = yaw_ref - state.yaw - switch = math.pi / 4.0 <= dyaw < math.pi / 2.0 - - if switch: - state.direction *= -1 - return 0.0 - - if state.direction != 1: - return -target_speed - - return target_speed - -def main(): - print("rear wheel feedback tracking start!!") - ax = [0.0, 6.0, 12.5, 5.0, 7.5, 3.0, -1.0] - ay = [0.0, 0.0, 5.0, 6.5, 3.0, 5.0, -2.0] - goal = [ax[-1], ay[-1]] - - reference_path = CubicSplinePath(ax, ay) - s = np.arange(0, reference_path.length, 0.1) - - t, x, y, yaw, v, goal_flag = simulate(reference_path, goal) - - # Test - assert goal_flag, "Cannot goal" - - if show_animation: # pragma: no cover - plt.close() - plt.subplots(1) - plt.plot(ax, ay, "xb", label="input") - plt.plot(reference_path.X(s), reference_path.Y(s), "-r", label="spline") - plt.plot(x, y, "-g", label="tracking") - plt.grid(True) - plt.axis("equal") - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.legend() - - plt.subplots(1) - plt.plot(s, np.rad2deg(reference_path.calc_yaw(s)), "-r", label="yaw") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("yaw angle[deg]") - - plt.subplots(1) - plt.plot(s, reference_path.calc_curvature(s), "-r", label="curvature") - plt.grid(True) - plt.legend() - plt.xlabel("line length[m]") - plt.ylabel("curvature [1/m]") - - plt.show() - -if __name__ == '__main__': - main() diff --git a/PathTracking/stanley_controller/stanley_controller.py b/PathTracking/stanley_controller/stanley_controller.py deleted file mode 100644 index bc98175f178..00000000000 --- a/PathTracking/stanley_controller/stanley_controller.py +++ /dev/null @@ -1,212 +0,0 @@ -""" - -Path tracking simulation with Stanley steering control and PID speed control. - -author: Atsushi Sakai (@Atsushi_twi) - -Ref: - - [Stanley: The robot that won the DARPA grand challenge](http://isl.ecst.csuchico.edu/DOCS/darpa2005/DARPA%202005%20Stanley.pdf) - - [Autonomous Automobile Path Tracking](https://www.ri.cmu.edu/pub_files/2009/2/Automatic_Steering_Methods_for_Autonomous_Automobile_Path_Tracking.pdf) - -""" -import numpy as np -import matplotlib.pyplot as plt -import sys -import pathlib - -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) -from utils.angle import angle_mod -from PathPlanning.CubicSpline import cubic_spline_planner - -k = 0.5 # control gain -Kp = 1.0 # speed proportional gain -dt = 0.1 # [s] time difference -L = 2.9 # [m] Wheel base of vehicle -max_steer = np.radians(30.0) # [rad] max steering angle - -show_animation = True - - -class State: - """ - Class representing the state of a vehicle. - - :param x: (float) x-coordinate - :param y: (float) y-coordinate - :param yaw: (float) yaw angle - :param v: (float) speed - """ - - def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0): - """Instantiate the object.""" - super().__init__() - self.x = x - self.y = y - self.yaw = yaw - self.v = v - - def update(self, acceleration, delta): - """ - Update the state of the vehicle. - - Stanley Control uses bicycle model. - - :param acceleration: (float) Acceleration - :param delta: (float) Steering - """ - delta = np.clip(delta, -max_steer, max_steer) - - self.x += self.v * np.cos(self.yaw) * dt - self.y += self.v * np.sin(self.yaw) * dt - self.yaw += self.v / L * np.tan(delta) * dt - self.yaw = normalize_angle(self.yaw) - self.v += acceleration * dt - - -def pid_control(target, current): - """ - Proportional control for the speed. - - :param target: (float) - :param current: (float) - :return: (float) - """ - return Kp * (target - current) - - -def stanley_control(state, cx, cy, cyaw, last_target_idx): - """ - Stanley steering control. - - :param state: (State object) - :param cx: ([float]) - :param cy: ([float]) - :param cyaw: ([float]) - :param last_target_idx: (int) - :return: (float, int) - """ - current_target_idx, error_front_axle = calc_target_index(state, cx, cy) - - if last_target_idx >= current_target_idx: - current_target_idx = last_target_idx - - # theta_e corrects the heading error - theta_e = normalize_angle(cyaw[current_target_idx] - state.yaw) - # theta_d corrects the cross track error - theta_d = np.arctan2(k * error_front_axle, state.v) - # Steering control - delta = theta_e + theta_d - - return delta, current_target_idx - - -def normalize_angle(angle): - """ - Normalize an angle to [-pi, pi]. - - :param angle: (float) - :return: (float) Angle in radian in [-pi, pi] - """ - return angle_mod(angle) - - -def calc_target_index(state, cx, cy): - """ - Compute index in the trajectory list of the target. - - :param state: (State object) - :param cx: [float] - :param cy: [float] - :return: (int, float) - """ - # Calc front axle position - fx = state.x + L * np.cos(state.yaw) - fy = state.y + L * np.sin(state.yaw) - - # Search nearest point index - dx = [fx - icx for icx in cx] - dy = [fy - icy for icy in cy] - d = np.hypot(dx, dy) - target_idx = np.argmin(d) - - # Project RMS error onto front axle vector - front_axle_vec = [-np.cos(state.yaw + np.pi / 2), - -np.sin(state.yaw + np.pi / 2)] - error_front_axle = np.dot([dx[target_idx], dy[target_idx]], front_axle_vec) - - return target_idx, error_front_axle - - -def main(): - """Plot an example of Stanley steering control on a cubic spline.""" - # target course - ax = [0.0, 100.0, 100.0, 50.0, 60.0] - ay = [0.0, 0.0, -30.0, -20.0, 0.0] - - cx, cy, cyaw, ck, s = cubic_spline_planner.calc_spline_course( - ax, ay, ds=0.1) - - target_speed = 30.0 / 3.6 # [m/s] - - max_simulation_time = 100.0 - - # Initial state - state = State(x=-0.0, y=5.0, yaw=np.radians(20.0), v=0.0) - - last_idx = len(cx) - 1 - time = 0.0 - x = [state.x] - y = [state.y] - yaw = [state.yaw] - v = [state.v] - t = [0.0] - target_idx, _ = calc_target_index(state, cx, cy) - - while max_simulation_time >= time and last_idx > target_idx: - ai = pid_control(target_speed, state.v) - di, target_idx = stanley_control(state, cx, cy, cyaw, target_idx) - state.update(ai, di) - - time += dt - - x.append(state.x) - y.append(state.y) - yaw.append(state.yaw) - v.append(state.v) - t.append(time) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect('key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(cx, cy, ".r", label="course") - plt.plot(x, y, "-b", label="trajectory") - plt.plot(cx[target_idx], cy[target_idx], "xg", label="target") - plt.axis("equal") - plt.grid(True) - plt.title("Speed[km/h]:" + str(state.v * 3.6)[:4]) - plt.pause(0.001) - - # Test - assert last_idx >= target_idx, "Cannot reach goal" - - if show_animation: # pragma: no cover - plt.plot(cx, cy, ".r", label="course") - plt.plot(x, y, "-b", label="trajectory") - plt.legend() - plt.xlabel("x[m]") - plt.ylabel("y[m]") - plt.axis("equal") - plt.grid(True) - - plt.subplots(1) - plt.plot(t, [iv * 3.6 for iv in v], "-r") - plt.xlabel("Time[s]") - plt.ylabel("Speed[km/h]") - plt.grid(True) - plt.show() - - -if __name__ == '__main__': - main() diff --git a/README.md b/README.md deleted file mode 100644 index 9e605435cee..00000000000 --- a/README.md +++ /dev/null @@ -1,658 +0,0 @@ -<img src="https://github.com/AtsushiSakai/PythonRobotics/raw/master/icon.png?raw=true" align="right" width="300" alt="header pic"/> - -# PythonRobotics - - - -[](https://ci.appveyor.com/project/AtsushiSakai/pythonrobotics) - -Python codes and [textbook](https://atsushisakai.github.io/PythonRobotics/index.html) for robotics algorithm. - - -# Table of Contents - * [What is this?](#what-is-this) - * [Requirements](#requirements) - * [Documentation](#documentation) - * [How to use](#how-to-use) - * [Localization](#localization) - * [Extended Kalman Filter localization](#extended-kalman-filter-localization) - * [Particle filter localization](#particle-filter-localization) - * [Histogram filter localization](#histogram-filter-localization) - * [Mapping](#mapping) - * [Gaussian grid map](#gaussian-grid-map) - * [Ray casting grid map](#ray-casting-grid-map) - * [Lidar to grid map](#lidar-to-grid-map) - * [k-means object clustering](#k-means-object-clustering) - * [Rectangle fitting](#rectangle-fitting) - * [SLAM](#slam) - * [Iterative Closest Point (ICP) Matching](#iterative-closest-point-icp-matching) - * [FastSLAM 1.0](#fastslam-10) - * [Path Planning](#path-planning) - * [Dynamic Window Approach](#dynamic-window-approach) - * [Grid based search](#grid-based-search) - * [Dijkstra algorithm](#dijkstra-algorithm) - * [A* algorithm](#a-algorithm) - * [D* algorithm](#d-algorithm) - * [D* Lite algorithm](#d-lite-algorithm) - * [Potential Field algorithm](#potential-field-algorithm) - * [Grid based coverage path planning](#grid-based-coverage-path-planning) - * [State Lattice Planning](#state-lattice-planning) - * [Biased polar sampling](#biased-polar-sampling) - * [Lane sampling](#lane-sampling) - * [Probabilistic Road-Map (PRM) planning](#probabilistic-road-map-prm-planning) - * [Rapidly-Exploring Random Trees (RRT)](#rapidly-exploring-random-trees-rrt) - * [RRT*](#rrt) - * [RRT* with reeds-shepp path](#rrt-with-reeds-shepp-path) - * [LQR-RRT*](#lqr-rrt) - * [Quintic polynomials planning](#quintic-polynomials-planning) - * [Reeds Shepp planning](#reeds-shepp-planning) - * [LQR based path planning](#lqr-based-path-planning) - * [Optimal Trajectory in a Frenet Frame](#optimal-trajectory-in-a-frenet-frame) - * [Path Tracking](#path-tracking) - * [move to a pose control](#move-to-a-pose-control) - * [Stanley control](#stanley-control) - * [Rear wheel feedback control](#rear-wheel-feedback-control) - * [Linear–quadratic regulator (LQR) speed and steering control](#linearquadratic-regulator-lqr-speed-and-steering-control) - * [Model predictive speed and steering control](#model-predictive-speed-and-steering-control) - * [Nonlinear Model predictive control with C-GMRES](#nonlinear-model-predictive-control-with-c-gmres) - * [Arm Navigation](#arm-navigation) - * [N joint arm to point control](#n-joint-arm-to-point-control) - * [Arm navigation with obstacle avoidance](#arm-navigation-with-obstacle-avoidance) - * [Aerial Navigation](#aerial-navigation) - * [drone 3d trajectory following](#drone-3d-trajectory-following) - * [rocket powered landing](#rocket-powered-landing) - * [Bipedal](#bipedal) - * [bipedal planner with inverted pendulum](#bipedal-planner-with-inverted-pendulum) - * [License](#license) - * [Use-case](#use-case) - * [Contribution](#contribution) - * [Citing](#citing) - * [Support](#support) - * [Sponsors](#sponsors) - * [JetBrains](#JetBrains) - * [1Password](#1password) - * [Authors](#authors) - -# What is PythonRobotics? - -PythonRobotics is a Python code collection and a [textbook](https://atsushisakai.github.io/PythonRobotics/index.html) of robotics algorithms. - -Features: - -1. Easy to read for understanding each algorithm's basic idea. - -2. Widely used and practical algorithms are selected. - -3. Minimum dependency. - -See this documentation - -- [Getting Started — PythonRobotics documentation](https://atsushisakai.github.io/PythonRobotics/getting_started.html#what-is-pythonrobotics) - -or this Youtube video: - -- [PythonRobotics project audio overview](https://www.youtube.com/watch?v=uMeRnNoJAfU) - -or this paper for more details: - -- [\[1808\.10703\] PythonRobotics: a Python code collection of robotics algorithms](https://arxiv.org/abs/1808.10703) ([BibTeX](https://github.com/AtsushiSakai/PythonRoboticsPaper/blob/master/python_robotics.bib)) - - -# Requirements to run the code - -For running each sample code: - -- [Python 3.12.x](https://www.python.org/) - -- [NumPy](https://numpy.org/) - -- [SciPy](https://scipy.org/) - -- [Matplotlib](https://matplotlib.org/) - -- [cvxpy](https://www.cvxpy.org/) - -For development: - -- [pytest](https://pytest.org/) (for unit tests) - -- [pytest-xdist](https://pypi.org/project/pytest-xdist/) (for parallel unit tests) - -- [mypy](https://mypy-lang.org/) (for type check) - -- [sphinx](https://www.sphinx-doc.org/) (for document generation) - -- [pycodestyle](https://pypi.org/project/pycodestyle/) (for code style check) - -# Documentation (Textbook) - -This README only shows some examples of this project. - -If you are interested in other examples or mathematical backgrounds of each algorithm, - -You can check the full documentation (textbook) online: [Welcome to PythonRobotics’s documentation\! — PythonRobotics documentation](https://atsushisakai.github.io/PythonRobotics/index.html) - -All animation gifs are stored here: [AtsushiSakai/PythonRoboticsGifs: Animation gifs of PythonRobotics](https://github.com/AtsushiSakai/PythonRoboticsGifs) - -# How to use - -1. Clone this repo. - - ```terminal - git clone https://github.com/AtsushiSakai/PythonRobotics.git - ``` - - -2. Install the required libraries. - -- using conda : - - ```terminal - conda env create -f requirements/environment.yml - ``` - -- using pip : - - ```terminal - pip install -r requirements/requirements.txt - ``` - - -3. Execute python script in each directory. - -4. Add star to this repo if you like it :smiley:. - -# Localization - -## Extended Kalman Filter localization - -<img src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/extended_kalman_filter/animation.gif" width="640" alt="EKF pic"> - -Ref: - -- [documentation](https://atsushisakai.github.io/PythonRobotics/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization.html) - -## Particle filter localization - - - -This is a sensor fusion localization with Particle Filter(PF). - -The blue line is true trajectory, the black line is dead reckoning trajectory, - -and the red line is an estimated trajectory with PF. - -It is assumed that the robot can measure a distance from landmarks (RFID). - -These measurements are used for PF localization. - -Ref: - -- [PROBABILISTIC ROBOTICS](http://www.probabilistic-robotics.org/) - - -## Histogram filter localization - - - -This is a 2D localization example with Histogram filter. - -The red cross is true position, black points are RFID positions. - -The blue grid shows a position probability of histogram filter. - -In this simulation, x,y are unknown, yaw is known. - -The filter integrates speed input and range observations from RFID for localization. - -Initial position is not needed. - -Ref: - -- [PROBABILISTIC ROBOTICS](http://www.probabilistic-robotics.org/) - -# Mapping - -## Gaussian grid map - -This is a 2D Gaussian grid mapping example. - - - -## Ray casting grid map - -This is a 2D ray casting grid mapping example. - - - -## Lidar to grid map - -This example shows how to convert a 2D range measurement to a grid map. - - - -## k-means object clustering - -This is a 2D object clustering with k-means algorithm. - - - -## Rectangle fitting - -This is a 2D rectangle fitting for vehicle detection. - - - - -# SLAM - -Simultaneous Localization and Mapping(SLAM) examples - -## Iterative Closest Point (ICP) Matching - -This is a 2D ICP matching example with singular value decomposition. - -It can calculate a rotation matrix, and a translation vector between points and points. - - - -Ref: - -- [Introduction to Mobile Robotics: Iterative Closest Point Algorithm](https://cs.gmu.edu/~kosecka/cs685/cs685-icp.pdf) - - -## FastSLAM 1.0 - -This is a feature based SLAM example using FastSLAM 1.0. - -The blue line is ground truth, the black line is dead reckoning, the red line is the estimated trajectory with FastSLAM. - -The red points are particles of FastSLAM. - -Black points are landmarks, blue crosses are estimated landmark positions by FastSLAM. - - - - - -Ref: - -- [PROBABILISTIC ROBOTICS](http://www.probabilistic-robotics.org/) - -- [SLAM simulations by Tim Bailey](http://www-personal.acfr.usyd.edu.au/tbailey/software/slam_simulations.htm) - - -# Path Planning - -## Dynamic Window Approach - -This is a 2D navigation sample code with Dynamic Window Approach. - -- [The Dynamic Window Approach to Collision Avoidance](https://www.ri.cmu.edu/pub_files/pub1/fox_dieter_1997_1/fox_dieter_1997_1.pdf) - - - - -## Grid based search - -### Dijkstra algorithm - -This is a 2D grid based the shortest path planning with Dijkstra's algorithm. - - - -In the animation, cyan points are searched nodes. - -### A\* algorithm - -This is a 2D grid based the shortest path planning with A star algorithm. - - - -In the animation, cyan points are searched nodes. - -Its heuristic is 2D Euclid distance. - -### D\* algorithm - -This is a 2D grid based the shortest path planning with D star algorithm. - - - -The animation shows a robot finding its path avoiding an obstacle using the D* search algorithm. - -Ref: - -- [D* Algorithm Wikipedia](https://en.wikipedia.org/wiki/D*) - -### D\* Lite algorithm - -This algorithm finds the shortest path between two points while rerouting when obstacles are discovered. It has been implemented here for a 2D grid. - - - -The animation shows a robot finding its path and rerouting to avoid obstacles as they are discovered using the D* Lite search algorithm. - -Refs: - -- [D* Lite](http://idm-lab.org/bib/abstracts/papers/aaai02b.pdf) -- [Improved Fast Replanning for Robot Navigation in Unknown Terrain](http://www.cs.cmu.edu/~maxim/files/dlite_icra02.pdf) - -### Potential Field algorithm - -This is a 2D grid based path planning with Potential Field algorithm. - - - -In the animation, the blue heat map shows potential value on each grid. - -Ref: - -- [Robotic Motion Planning:Potential Functions](https://www.cs.cmu.edu/~motionplanning/lecture/Chap4-Potential-Field_howie.pdf) - -### Grid based coverage path planning - -This is a 2D grid based coverage path planning simulation. - - - -## State Lattice Planning - -This script is a path planning code with state lattice planning. - -This code uses the model predictive trajectory generator to solve boundary problem. - -Ref: - -- [Optimal rough terrain trajectory generation for wheeled mobile robots](https://journals.sagepub.com/doi/pdf/10.1177/0278364906075328) - -- [State Space Sampling of Feasible Motions for High-Performance Mobile Robot Navigation in Complex Environments](https://www.frc.ri.cmu.edu/~alonzo/pubs/papers/JFR_08_SS_Sampling.pdf) - - -### Biased polar sampling - - - - -### Lane sampling - - - -## Probabilistic Road-Map (PRM) planning - - - -This PRM planner uses Dijkstra method for graph search. - -In the animation, blue points are sampled points, - -Cyan crosses means searched points with Dijkstra method, - -The red line is the final path of PRM. - -Ref: - -- [Probabilistic roadmap \- Wikipedia](https://en.wikipedia.org/wiki/Probabilistic_roadmap) - - - -## Rapidly-Exploring Random Trees (RRT) - -### RRT\* - - - -This is a path planning code with RRT\* - -Black circles are obstacles, green line is a searched tree, red crosses are start and goal positions. - -Ref: - -- [Incremental Sampling-based Algorithms for Optimal Motion Planning](https://arxiv.org/abs/1005.0416) - -- [Sampling-based Algorithms for Optimal Motion Planning](https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=bddbc99f97173430aa49a0ada53ab5bade5902fa) - -### RRT\* with reeds-shepp path - - - -Path planning for a car robot with RRT\* and reeds shepp path planner. - -### LQR-RRT\* - -This is a path planning simulation with LQR-RRT\*. - -A double integrator motion model is used for LQR local planner. - - - -Ref: - -- [LQR\-RRT\*: Optimal Sampling\-Based Motion Planning with Automatically Derived Extension Heuristics](https://lis.csail.mit.edu/pubs/perez-icra12.pdf) - -- [MahanFathi/LQR\-RRTstar: LQR\-RRT\* method is used for random motion planning of a simple pendulum in its phase plot](https://github.com/MahanFathi/LQR-RRTstar) - - -## Quintic polynomials planning - -Motion planning with quintic polynomials. - - - -It can calculate a 2D path, velocity, and acceleration profile based on quintic polynomials. - -Ref: - -- [Local Path Planning And Motion Control For Agv In Positioning](https://ieeexplore.ieee.org/document/637936/) - -## Reeds Shepp planning - -A sample code with Reeds Shepp path planning. - - - -Ref: - -- [15.3.2 Reeds\-Shepp Curves](http://planning.cs.uiuc.edu/node822.html) - -- [optimal paths for a car that goes both forwards and backwards](https://pdfs.semanticscholar.org/932e/c495b1d0018fd59dee12a0bf74434fac7af4.pdf) - -- [ghliu/pyReedsShepp: Implementation of Reeds Shepp curve\.](https://github.com/ghliu/pyReedsShepp) - - -## LQR based path planning - -A sample code using LQR based path planning for double integrator model. - - - - -## Optimal Trajectory in a Frenet Frame - - - -This is optimal trajectory generation in a Frenet Frame. - -The cyan line is the target course and black crosses are obstacles. - -The red line is the predicted path. - -Ref: - -- [Optimal Trajectory Generation for Dynamic Street Scenarios in a Frenet Frame](https://www.researchgate.net/profile/Moritz_Werling/publication/224156269_Optimal_Trajectory_Generation_for_Dynamic_Street_Scenarios_in_a_Frenet_Frame/links/54f749df0cf210398e9277af.pdf) - -- [Optimal trajectory generation for dynamic street scenarios in a Frenet Frame](https://www.youtube.com/watch?v=Cj6tAQe7UCY) - - -# Path Tracking - -## move to a pose control - -This is a simulation of moving to a pose control - - - -Ref: - -- [P. I. Corke, "Robotics, Vision and Control" \| SpringerLink p102](https://link.springer.com/book/10.1007/978-3-642-20144-8) - - -## Stanley control - -Path tracking simulation with Stanley steering control and PID speed control. - - - -Ref: - -- [Stanley: The robot that won the DARPA grand challenge](http://robots.stanford.edu/papers/thrun.stanley05.pdf) - -- [Automatic Steering Methods for Autonomous Automobile Path Tracking](https://www.ri.cmu.edu/pub_files/2009/2/Automatic_Steering_Methods_for_Autonomous_Automobile_Path_Tracking.pdf) - - - -## Rear wheel feedback control - -Path tracking simulation with rear wheel feedback steering control and PID speed control. - - - -Ref: - -- [A Survey of Motion Planning and Control Techniques for Self-driving Urban Vehicles](https://arxiv.org/abs/1604.07446) - - -## Linear–quadratic regulator (LQR) speed and steering control - -Path tracking simulation with LQR speed and steering control. - - - -Ref: - -- [Towards fully autonomous driving: Systems and algorithms \- IEEE Conference Publication](https://ieeexplore.ieee.org/document/5940562/) - - -## Model predictive speed and steering control - -Path tracking simulation with iterative linear model predictive speed and steering control. - -<img src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/model_predictive_speed_and_steer_control/animation.gif" width="640" alt="MPC pic"> - -Ref: - -- [documentation](https://atsushisakai.github.io/PythonRobotics/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html) - -- [Real\-time Model Predictive Control \(MPC\), ACADO, Python \| Work\-is\-Playing](http://grauonline.de/wordpress/?page_id=3244) - -## Nonlinear Model predictive control with C-GMRES - -A motion planning and path tracking simulation with NMPC of C-GMRES - - - -Ref: - -- [documentation](https://atsushisakai.github.io/PythonRobotics/modules/path_tracking/cgmres_nmpc/cgmres_nmpc.html) - - -# Arm Navigation - -## N joint arm to point control - -N joint arm to a point control simulation. - -This is an interactive simulation. - -You can set the goal position of the end effector with left-click on the plotting area. - - - -In this simulation N = 10, however, you can change it. - -## Arm navigation with obstacle avoidance - -Arm navigation with obstacle avoidance simulation. - - - - -# Aerial Navigation - -## drone 3d trajectory following - -This is a 3d trajectory following simulation for a quadrotor. - - - -## rocket powered landing - -This is a 3d trajectory generation simulation for a rocket powered landing. - - - -Ref: - -- [documentation](https://atsushisakai.github.io/PythonRobotics/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing.html) - -# Bipedal - -## bipedal planner with inverted pendulum - -This is a bipedal planner for modifying footsteps for an inverted pendulum. - -You can set the footsteps, and the planner will modify those automatically. - - - -# License - -MIT - -# Use-case - -If this project helps your robotics project, please let me know with creating an issue. - -Your robot's video, which is using PythonRobotics, is very welcome!! - -This is a list of user's comment and references:[users\_comments](https://github.com/AtsushiSakai/PythonRobotics/blob/master/users_comments.md) - -# Contribution - -Any contribution is welcome!! - -Please check this document:[How To Contribute — PythonRobotics documentation](https://atsushisakai.github.io/PythonRobotics/modules/0_getting_started/3_how_to_contribute.html) - -# Citing - -If you use this project's code for your academic work, we encourage you to cite [our papers](https://arxiv.org/abs/1808.10703) - -If you use this project's code in industry, we'd love to hear from you as well; feel free to reach out to the developers directly. - -# <a id="support"></a>Supporting this project - -If you or your company would like to support this project, please consider: - -- [Sponsor @AtsushiSakai on GitHub Sponsors](https://github.com/sponsors/AtsushiSakai) - -- [Become a backer or sponsor on Patreon](https://www.patreon.com/myenigma) - -- [One-time donation via PayPal](https://www.paypal.com/paypalme/myenigmapay/) - -If you would like to support us in some other way, please contact with creating an issue. - -## <a id="sponsors"></a>Sponsors - -### <a id="JetBrains"></a>[JetBrains](https://www.jetbrains.com/) - -They are providing a free license of their IDEs for this OSS development. - -### [1Password](https://github.com/1Password/for-open-source) - -They are providing a free license of their 1Password team license for this OSS project. - - -# Authors - -- [Contributors to AtsushiSakai/PythonRobotics](https://github.com/AtsushiSakai/PythonRobotics/graphs/contributors) - diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 53dcafa450c..00000000000 --- a/SECURITY.md +++ /dev/null @@ -1,13 +0,0 @@ -# Security Policy - -## Supported Versions - -In this project, we are only support latest code. - -| Version | Supported | -| ------- | ------------------ | -| latest | :white_check_mark: | - -## Reporting a Vulnerability - -If you find any security related problem, let us know by creating an issue about it. diff --git a/SLAM/EKFSLAM/ekf_slam.py b/SLAM/EKFSLAM/ekf_slam.py deleted file mode 100644 index 5c4417d7c34..00000000000 --- a/SLAM/EKFSLAM/ekf_slam.py +++ /dev/null @@ -1,263 +0,0 @@ -""" -Extended Kalman Filter SLAM example - -author: Atsushi Sakai (@Atsushi_twi) -""" - -import math - -import matplotlib.pyplot as plt -import numpy as np -from utils.angle import angle_mod - -# EKF state covariance -Cx = np.diag([0.5, 0.5, np.deg2rad(30.0)]) ** 2 - -# Simulation parameter -Q_sim = np.diag([0.2, np.deg2rad(1.0)]) ** 2 -R_sim = np.diag([1.0, np.deg2rad(10.0)]) ** 2 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] -MAX_RANGE = 20.0 # maximum observation range -M_DIST_TH = 2.0 # Threshold of Mahalanobis distance for data association. -STATE_SIZE = 3 # State size [x,y,yaw] -LM_SIZE = 2 # LM state size [x,y] - -show_animation = True - - -def ekf_slam(xEst, PEst, u, z): - # Predict - G, Fx = jacob_motion(xEst, u) - xEst[0:STATE_SIZE] = motion_model(xEst[0:STATE_SIZE], u) - PEst = G.T @ PEst @ G + Fx.T @ Cx @ Fx - initP = np.eye(2) - - # Update - for iz in range(len(z[:, 0])): # for each observation - min_id = search_correspond_landmark_id(xEst, PEst, z[iz, 0:2]) - - nLM = calc_n_lm(xEst) - if min_id == nLM: - print("New LM") - # Extend state and covariance matrix - xAug = np.vstack((xEst, calc_landmark_position(xEst, z[iz, :]))) - PAug = np.vstack((np.hstack((PEst, np.zeros((len(xEst), LM_SIZE)))), - np.hstack((np.zeros((LM_SIZE, len(xEst))), initP)))) - xEst = xAug - PEst = PAug - lm = get_landmark_position_from_state(xEst, min_id) - y, S, H = calc_innovation(lm, xEst, PEst, z[iz, 0:2], min_id) - - K = (PEst @ H.T) @ np.linalg.inv(S) - xEst = xEst + (K @ y) - PEst = (np.eye(len(xEst)) - (K @ H)) @ PEst - - xEst[2] = pi_2_pi(xEst[2]) - - return xEst, PEst - - -def calc_input(): - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - u = np.array([[v, yaw_rate]]).T - return u - - -def observation(xTrue, xd, u, RFID): - xTrue = motion_model(xTrue, u) - - # add noise to gps x-y - z = np.zeros((0, 3)) - - for i in range(len(RFID[:, 0])): - - dx = RFID[i, 0] - xTrue[0, 0] - dy = RFID[i, 1] - xTrue[1, 0] - d = math.hypot(dx, dy) - angle = pi_2_pi(math.atan2(dy, dx) - xTrue[2, 0]) - if d <= MAX_RANGE: - dn = d + np.random.randn() * Q_sim[0, 0] ** 0.5 # add noise - angle_n = angle + np.random.randn() * Q_sim[1, 1] ** 0.5 # add noise - zi = np.array([dn, angle_n, i]) - z = np.vstack((z, zi)) - - # add noise to input - ud = np.array([[ - u[0, 0] + np.random.randn() * R_sim[0, 0] ** 0.5, - u[1, 0] + np.random.randn() * R_sim[1, 1] ** 0.5]]).T - - xd = motion_model(xd, ud) - return xTrue, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0], - [0, 1.0, 0], - [0, 0, 1.0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT]]) - - x = (F @ x) + (B @ u) - return x - - -def calc_n_lm(x): - n = int((len(x) - STATE_SIZE) / LM_SIZE) - return n - - -def jacob_motion(x, u): - Fx = np.hstack((np.eye(STATE_SIZE), np.zeros( - (STATE_SIZE, LM_SIZE * calc_n_lm(x))))) - - jF = np.array([[0.0, 0.0, -DT * u[0, 0] * math.sin(x[2, 0])], - [0.0, 0.0, DT * u[0, 0] * math.cos(x[2, 0])], - [0.0, 0.0, 0.0]], dtype=float) - - G = np.eye(len(x)) + Fx.T @ jF @ Fx - - return G, Fx, - - -def calc_landmark_position(x, z): - zp = np.zeros((2, 1)) - - zp[0, 0] = x[0, 0] + z[0] * math.cos(x[2, 0] + z[1]) - zp[1, 0] = x[1, 0] + z[0] * math.sin(x[2, 0] + z[1]) - - return zp - - -def get_landmark_position_from_state(x, ind): - lm = x[STATE_SIZE + LM_SIZE * ind: STATE_SIZE + LM_SIZE * (ind + 1), :] - - return lm - - -def search_correspond_landmark_id(xAug, PAug, zi): - """ - Landmark association with Mahalanobis distance - """ - - nLM = calc_n_lm(xAug) - - min_dist = [] - - for i in range(nLM): - lm = get_landmark_position_from_state(xAug, i) - y, S, H = calc_innovation(lm, xAug, PAug, zi, i) - min_dist.append(y.T @ np.linalg.inv(S) @ y) - - min_dist.append(M_DIST_TH) # new landmark - - min_id = min_dist.index(min(min_dist)) - - return min_id - - -def calc_innovation(lm, xEst, PEst, z, LMid): - delta = lm - xEst[0:2] - q = (delta.T @ delta)[0, 0] - z_angle = math.atan2(delta[1, 0], delta[0, 0]) - xEst[2, 0] - zp = np.array([[math.sqrt(q), pi_2_pi(z_angle)]]) - y = (z - zp).T - y[1] = pi_2_pi(y[1]) - H = jacob_h(q, delta, xEst, LMid + 1) - S = H @ PEst @ H.T + Cx[0:2, 0:2] - - return y, S, H - - -def jacob_h(q, delta, x, i): - sq = math.sqrt(q) - G = np.array([[-sq * delta[0, 0], - sq * delta[1, 0], 0, sq * delta[0, 0], sq * delta[1, 0]], - [delta[1, 0], - delta[0, 0], - q, - delta[1, 0], delta[0, 0]]]) - - G = G / q - nLM = calc_n_lm(x) - F1 = np.hstack((np.eye(3), np.zeros((3, 2 * nLM)))) - F2 = np.hstack((np.zeros((2, 3)), np.zeros((2, 2 * (i - 1))), - np.eye(2), np.zeros((2, 2 * nLM - 2 * i)))) - - F = np.vstack((F1, F2)) - - H = G @ F - - return H - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # RFID positions [x, y] - RFID = np.array([[10.0, -2.0], - [15.0, 10.0], - [3.0, 15.0], - [-5.0, 20.0]]) - - # State Vector [x y yaw v]' - xEst = np.zeros((STATE_SIZE, 1)) - xTrue = np.zeros((STATE_SIZE, 1)) - PEst = np.eye(STATE_SIZE) - - xDR = np.zeros((STATE_SIZE, 1)) # Dead reckoning - - # history - hxEst = xEst - hxTrue = xTrue - hxDR = xTrue - - while SIM_TIME >= time: - time += DT - u = calc_input() - - xTrue, z, xDR, ud = observation(xTrue, xDR, u, RFID) - - xEst, PEst = ekf_slam(xEst, PEst, ud, z) - - x_state = xEst[0:STATE_SIZE] - - # store data history - hxEst = np.hstack((hxEst, x_state)) - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - - plt.plot(RFID[:, 0], RFID[:, 1], "*k") - plt.plot(xEst[0], xEst[1], ".r") - - # plot landmark - for i in range(calc_n_lm(xEst)): - plt.plot(xEst[STATE_SIZE + i * 2], - xEst[STATE_SIZE + i * 2 + 1], "xg") - - plt.plot(hxTrue[0, :], - hxTrue[1, :], "-b") - plt.plot(hxDR[0, :], - hxDR[1, :], "-k") - plt.plot(hxEst[0, :], - hxEst[1, :], "-r") - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/SLAM/FastSLAM1/fast_slam1.py b/SLAM/FastSLAM1/fast_slam1.py deleted file mode 100644 index 98f8a664177..00000000000 --- a/SLAM/FastSLAM1/fast_slam1.py +++ /dev/null @@ -1,394 +0,0 @@ -""" - -FastSLAM 1.0 example - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math - -import matplotlib.pyplot as plt -import numpy as np -from utils.angle import angle_mod - -# Fast SLAM covariance -Q = np.diag([3.0, np.deg2rad(10.0)]) ** 2 -R = np.diag([1.0, np.deg2rad(20.0)]) ** 2 - -# Simulation parameter -Q_SIM = np.diag([0.3, np.deg2rad(2.0)]) ** 2 -R_SIM = np.diag([0.5, np.deg2rad(10.0)]) ** 2 -OFFSET_YAW_RATE_NOISE = 0.01 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] -MAX_RANGE = 20.0 # maximum observation range -M_DIST_TH = 2.0 # Threshold of Mahalanobis distance for data association. -STATE_SIZE = 3 # State size [x,y,yaw] -LM_SIZE = 2 # LM state size [x,y] -N_PARTICLE = 100 # number of particle -NTH = N_PARTICLE / 1.5 # Number of particle for re-sampling - -show_animation = True - - -class Particle: - - def __init__(self, n_landmark): - self.w = 1.0 / N_PARTICLE - self.x = 0.0 - self.y = 0.0 - self.yaw = 0.0 - # landmark x-y positions - self.lm = np.zeros((n_landmark, LM_SIZE)) - # landmark position covariance - self.lmP = np.zeros((n_landmark * LM_SIZE, LM_SIZE)) - - -def fast_slam1(particles, u, z): - particles = predict_particles(particles, u) - - particles = update_with_observation(particles, z) - - particles = resampling(particles) - - return particles - - -def normalize_weight(particles): - sum_w = sum([p.w for p in particles]) - - try: - for i in range(N_PARTICLE): - particles[i].w /= sum_w - except ZeroDivisionError: - for i in range(N_PARTICLE): - particles[i].w = 1.0 / N_PARTICLE - - return particles - - return particles - - -def calc_final_state(particles): - x_est = np.zeros((STATE_SIZE, 1)) - - particles = normalize_weight(particles) - - for i in range(N_PARTICLE): - x_est[0, 0] += particles[i].w * particles[i].x - x_est[1, 0] += particles[i].w * particles[i].y - x_est[2, 0] += particles[i].w * particles[i].yaw - - x_est[2, 0] = pi_2_pi(x_est[2, 0]) - - return x_est - - -def predict_particles(particles, u): - for i in range(N_PARTICLE): - px = np.zeros((STATE_SIZE, 1)) - px[0, 0] = particles[i].x - px[1, 0] = particles[i].y - px[2, 0] = particles[i].yaw - ud = u + (np.random.randn(1, 2) @ R ** 0.5).T # add noise - px = motion_model(px, ud) - particles[i].x = px[0, 0] - particles[i].y = px[1, 0] - particles[i].yaw = px[2, 0] - - return particles - - -def add_new_landmark(particle, z, Q_cov): - r = z[0] - b = z[1] - lm_id = int(z[2]) - - s = math.sin(pi_2_pi(particle.yaw + b)) - c = math.cos(pi_2_pi(particle.yaw + b)) - - particle.lm[lm_id, 0] = particle.x + r * c - particle.lm[lm_id, 1] = particle.y + r * s - - # covariance - dx = r * c - dy = r * s - d2 = dx**2 + dy**2 - d = math.sqrt(d2) - Gz = np.array([[dx / d, dy / d], - [-dy / d2, dx / d2]]) - particle.lmP[2 * lm_id:2 * lm_id + 2] = np.linalg.inv( - Gz) @ Q_cov @ np.linalg.inv(Gz.T) - - return particle - - -def compute_jacobians(particle, xf, Pf, Q_cov): - dx = xf[0, 0] - particle.x - dy = xf[1, 0] - particle.y - d2 = dx ** 2 + dy ** 2 - d = math.sqrt(d2) - - zp = np.array( - [d, pi_2_pi(math.atan2(dy, dx) - particle.yaw)]).reshape(2, 1) - - Hv = np.array([[-dx / d, -dy / d, 0.0], - [dy / d2, -dx / d2, -1.0]]) - - Hf = np.array([[dx / d, dy / d], - [-dy / d2, dx / d2]]) - - Sf = Hf @ Pf @ Hf.T + Q_cov - - return zp, Hv, Hf, Sf - - -def update_kf_with_cholesky(xf, Pf, v, Q_cov, Hf): - PHt = Pf @ Hf.T - S = Hf @ PHt + Q_cov - - S = (S + S.T) * 0.5 - s_chol = np.linalg.cholesky(S).T - s_chol_inv = np.linalg.inv(s_chol) - W1 = PHt @ s_chol_inv - W = W1 @ s_chol_inv.T - - x = xf + W @ v - P = Pf - W1 @ W1.T - - return x, P - - -def update_landmark(particle, z, Q_cov): - lm_id = int(z[2]) - xf = np.array(particle.lm[lm_id, :]).reshape(2, 1) - Pf = np.array(particle.lmP[2 * lm_id:2 * lm_id + 2, :]) - - zp, Hv, Hf, Sf = compute_jacobians(particle, xf, Pf, Q) - - dz = z[0:2].reshape(2, 1) - zp - dz[1, 0] = pi_2_pi(dz[1, 0]) - - xf, Pf = update_kf_with_cholesky(xf, Pf, dz, Q_cov, Hf) - - particle.lm[lm_id, :] = xf.T - particle.lmP[2 * lm_id:2 * lm_id + 2, :] = Pf - - return particle - - -def compute_weight(particle, z, Q_cov): - lm_id = int(z[2]) - xf = np.array(particle.lm[lm_id, :]).reshape(2, 1) - Pf = np.array(particle.lmP[2 * lm_id:2 * lm_id + 2]) - zp, Hv, Hf, Sf = compute_jacobians(particle, xf, Pf, Q_cov) - - dx = z[0:2].reshape(2, 1) - zp - dx[1, 0] = pi_2_pi(dx[1, 0]) - - try: - invS = np.linalg.inv(Sf) - except np.linalg.linalg.LinAlgError: - print("singular") - return 1.0 - - num = np.exp(-0.5 * (dx.T @ invS @ dx))[0, 0] - den = 2.0 * math.pi * math.sqrt(np.linalg.det(Sf)) - - w = num / den - - return w - - -def update_with_observation(particles, z): - for iz in range(len(z[0, :])): - - landmark_id = int(z[2, iz]) - - for ip in range(N_PARTICLE): - # new landmark - if abs(particles[ip].lm[landmark_id, 0]) <= 0.01: - particles[ip] = add_new_landmark(particles[ip], z[:, iz], Q) - # known landmark - else: - w = compute_weight(particles[ip], z[:, iz], Q) - particles[ip].w *= w - particles[ip] = update_landmark(particles[ip], z[:, iz], Q) - - return particles - - -def resampling(particles): - """ - low variance re-sampling - """ - - particles = normalize_weight(particles) - - pw = [] - for i in range(N_PARTICLE): - pw.append(particles[i].w) - - pw = np.array(pw) - - n_eff = 1.0 / (pw @ pw.T) # Effective particle number - - if n_eff < NTH: # resampling - w_cum = np.cumsum(pw) - base = np.cumsum(pw * 0.0 + 1 / N_PARTICLE) - 1 / N_PARTICLE - resample_id = base + np.random.rand(base.shape[0]) / N_PARTICLE - - indexes = [] - index = 0 - for ip in range(N_PARTICLE): - while (index < w_cum.shape[0] - 1) \ - and (resample_id[ip] > w_cum[index]): - index += 1 - indexes.append(index) - - tmp_particles = particles[:] - for i in range(len(indexes)): - particles[i].x = tmp_particles[indexes[i]].x - particles[i].y = tmp_particles[indexes[i]].y - particles[i].yaw = tmp_particles[indexes[i]].yaw - particles[i].lm = tmp_particles[indexes[i]].lm[:, :] - particles[i].lmP = tmp_particles[indexes[i]].lmP[:, :] - particles[i].w = 1.0 / N_PARTICLE - - return particles - - -def calc_input(time): - if time <= 3.0: # wait at first - v = 0.0 - yaw_rate = 0.0 - else: - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - - u = np.array([v, yaw_rate]).reshape(2, 1) - - return u - - -def observation(x_true, xd, u, rfid): - # calc true state - x_true = motion_model(x_true, u) - - # add noise to range observation - z = np.zeros((3, 0)) - for i in range(len(rfid[:, 0])): - - dx = rfid[i, 0] - x_true[0, 0] - dy = rfid[i, 1] - x_true[1, 0] - d = math.hypot(dx, dy) - angle = pi_2_pi(math.atan2(dy, dx) - x_true[2, 0]) - if d <= MAX_RANGE: - dn = d + np.random.randn() * Q_SIM[0, 0] ** 0.5 # add noise - angle_with_noize = angle + np.random.randn() * Q_SIM[ - 1, 1] ** 0.5 # add noise - zi = np.array([dn, pi_2_pi(angle_with_noize), i]).reshape(3, 1) - z = np.hstack((z, zi)) - - # add noise to input - ud1 = u[0, 0] + np.random.randn() * R_SIM[0, 0] ** 0.5 - ud2 = u[1, 0] + np.random.randn() * R_SIM[ - 1, 1] ** 0.5 + OFFSET_YAW_RATE_NOISE - ud = np.array([ud1, ud2]).reshape(2, 1) - - xd = motion_model(xd, ud) - - return x_true, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0], - [0, 1.0, 0], - [0, 0, 1.0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT]]) - - x = F @ x + B @ u - - x[2, 0] = pi_2_pi(x[2, 0]) - - return x - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # RFID positions [x, y] - rfid = np.array([[10.0, -2.0], - [15.0, 10.0], - [15.0, 15.0], - [10.0, 20.0], - [3.0, 15.0], - [-5.0, 20.0], - [-5.0, 5.0], - [-10.0, 15.0] - ]) - n_landmark = rfid.shape[0] - - # State Vector [x y yaw v]' - x_est = np.zeros((STATE_SIZE, 1)) # SLAM estimation - x_true = np.zeros((STATE_SIZE, 1)) # True state - x_dr = np.zeros((STATE_SIZE, 1)) # Dead reckoning - - # history - hist_x_est = x_est - hist_x_true = x_true - hist_x_dr = x_dr - - particles = [Particle(n_landmark) for _ in range(N_PARTICLE)] - - while SIM_TIME >= time: - time += DT - u = calc_input(time) - - x_true, z, x_dr, ud = observation(x_true, x_dr, u, rfid) - - particles = fast_slam1(particles, ud, z) - - x_est = calc_final_state(particles) - - x_state = x_est[0: STATE_SIZE] - - # store data history - hist_x_est = np.hstack((hist_x_est, x_state)) - hist_x_dr = np.hstack((hist_x_dr, x_dr)) - hist_x_true = np.hstack((hist_x_true, x_true)) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', lambda event: - [exit(0) if event.key == 'escape' else None]) - plt.plot(rfid[:, 0], rfid[:, 1], "*k") - - for i in range(N_PARTICLE): - plt.plot(particles[i].x, particles[i].y, ".r") - plt.plot(particles[i].lm[:, 0], particles[i].lm[:, 1], "xb") - - plt.plot(hist_x_true[0, :], hist_x_true[1, :], "-b") - plt.plot(hist_x_dr[0, :], hist_x_dr[1, :], "-k") - plt.plot(hist_x_est[0, :], hist_x_est[1, :], "-r") - plt.plot(x_est[0], x_est[1], "xk") - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/SLAM/FastSLAM2/fast_slam2.py b/SLAM/FastSLAM2/fast_slam2.py deleted file mode 100644 index d4cf0d84ddd..00000000000 --- a/SLAM/FastSLAM2/fast_slam2.py +++ /dev/null @@ -1,426 +0,0 @@ -""" - -FastSLAM 2.0 example - -author: Atsushi Sakai (@Atsushi_twi) - -""" - -import math - -import matplotlib.pyplot as plt -import numpy as np -from utils.angle import angle_mod - -# Fast SLAM covariance -Q = np.diag([3.0, np.deg2rad(10.0)]) ** 2 -R = np.diag([1.0, np.deg2rad(20.0)]) ** 2 - -# Simulation parameter -Q_SIM = np.diag([0.3, np.deg2rad(2.0)]) ** 2 -R_SIM = np.diag([0.5, np.deg2rad(10.0)]) ** 2 -OFFSET_YAW_RATE_NOISE = 0.01 - -DT = 0.1 # time tick [s] -SIM_TIME = 50.0 # simulation time [s] -MAX_RANGE = 20.0 # maximum observation range -M_DIST_TH = 2.0 # Threshold of Mahalanobis distance for data association. -STATE_SIZE = 3 # State size [x,y,yaw] -LM_SIZE = 2 # LM state size [x,y] -N_PARTICLE = 100 # number of particle -NTH = N_PARTICLE / 1.5 # Number of particle for re-sampling - -show_animation = True - - -class Particle: - - def __init__(self, n_landmark): - self.w = 1.0 / N_PARTICLE - self.x = 0.0 - self.y = 0.0 - self.yaw = 0.0 - self.P = np.eye(3) - # landmark x-y positions - self.lm = np.zeros((n_landmark, LM_SIZE)) - # landmark position covariance - self.lmP = np.zeros((n_landmark * LM_SIZE, LM_SIZE)) - - -def fast_slam2(particles, u, z): - particles = predict_particles(particles, u) - - particles = update_with_observation(particles, z) - - particles = resampling(particles) - - return particles - - -def normalize_weight(particles): - sum_w = sum([p.w for p in particles]) - - try: - for i in range(N_PARTICLE): - particles[i].w /= sum_w - except ZeroDivisionError: - for i in range(N_PARTICLE): - particles[i].w = 1.0 / N_PARTICLE - - return particles - - return particles - - -def calc_final_state(particles): - x_est = np.zeros((STATE_SIZE, 1)) - - particles = normalize_weight(particles) - - for i in range(N_PARTICLE): - x_est[0, 0] += particles[i].w * particles[i].x - x_est[1, 0] += particles[i].w * particles[i].y - x_est[2, 0] += particles[i].w * particles[i].yaw - - x_est[2, 0] = pi_2_pi(x_est[2, 0]) - - return x_est - - -def predict_particles(particles, u): - for i in range(N_PARTICLE): - px = np.zeros((STATE_SIZE, 1)) - px[0, 0] = particles[i].x - px[1, 0] = particles[i].y - px[2, 0] = particles[i].yaw - ud = u + (np.random.randn(1, 2) @ R ** 0.5).T # add noise - px = motion_model(px, ud) - particles[i].x = px[0, 0] - particles[i].y = px[1, 0] - particles[i].yaw = px[2, 0] - - return particles - - -def add_new_lm(particle, z, Q_cov): - r = z[0] - b = z[1] - lm_id = int(z[2]) - - s = math.sin(pi_2_pi(particle.yaw + b)) - c = math.cos(pi_2_pi(particle.yaw + b)) - - particle.lm[lm_id, 0] = particle.x + r * c - particle.lm[lm_id, 1] = particle.y + r * s - - # covariance - dx = r * c - dy = r * s - d2 = dx ** 2 + dy ** 2 - d = math.sqrt(d2) - Gz = np.array([[dx / d, dy / d], - [-dy / d2, dx / d2]]) - particle.lmP[2 * lm_id:2 * lm_id + 2] = np.linalg.inv( - Gz) @ Q_cov @ np.linalg.inv(Gz.T) - - return particle - - -def compute_jacobians(particle, xf, Pf, Q_cov): - dx = xf[0, 0] - particle.x - dy = xf[1, 0] - particle.y - d2 = dx ** 2 + dy ** 2 - d = math.sqrt(d2) - - zp = np.array( - [d, pi_2_pi(math.atan2(dy, dx) - particle.yaw)]).reshape(2, 1) - - Hv = np.array([[-dx / d, -dy / d, 0.0], - [dy / d2, -dx / d2, -1.0]]) - - Hf = np.array([[dx / d, dy / d], - [-dy / d2, dx / d2]]) - - Sf = Hf @ Pf @ Hf.T + Q_cov - - return zp, Hv, Hf, Sf - - -def update_kf_with_cholesky(xf, Pf, v, Q_cov, Hf): - PHt = Pf @ Hf.T - S = Hf @ PHt + Q_cov - - S = (S + S.T) * 0.5 - SChol = np.linalg.cholesky(S).T - SCholInv = np.linalg.inv(SChol) - W1 = PHt @ SCholInv - W = W1 @ SCholInv.T - - x = xf + W @ v - P = Pf - W1 @ W1.T - - return x, P - - -def update_landmark(particle, z, Q_cov): - lm_id = int(z[2]) - xf = np.array(particle.lm[lm_id, :]).reshape(2, 1) - Pf = np.array(particle.lmP[2 * lm_id:2 * lm_id + 2]) - - zp, Hv, Hf, Sf = compute_jacobians(particle, xf, Pf, Q_cov) - - dz = z[0:2].reshape(2, 1) - zp - dz[1, 0] = pi_2_pi(dz[1, 0]) - - xf, Pf = update_kf_with_cholesky(xf, Pf, dz, Q, Hf) - - particle.lm[lm_id, :] = xf.T - particle.lmP[2 * lm_id:2 * lm_id + 2, :] = Pf - - return particle - - -def compute_weight(particle, z, Q_cov): - lm_id = int(z[2]) - xf = np.array(particle.lm[lm_id, :]).reshape(2, 1) - Pf = np.array(particle.lmP[2 * lm_id:2 * lm_id + 2]) - zp, Hv, Hf, Sf = compute_jacobians(particle, xf, Pf, Q_cov) - - dz = z[0:2].reshape(2, 1) - zp - dz[1, 0] = pi_2_pi(dz[1, 0]) - - try: - invS = np.linalg.inv(Sf) - except np.linalg.linalg.LinAlgError: - return 1.0 - - num = np.exp(-0.5 * dz.T @ invS @ dz)[0, 0] - den = 2.0 * math.pi * math.sqrt(np.linalg.det(Sf)) - - w = num / den - - return w - - -def proposal_sampling(particle, z, Q_cov): - lm_id = int(z[2]) - xf = particle.lm[lm_id, :].reshape(2, 1) - Pf = particle.lmP[2 * lm_id:2 * lm_id + 2] - # State - x = np.array([particle.x, particle.y, particle.yaw]).reshape(3, 1) - P = particle.P - zp, Hv, Hf, Sf = compute_jacobians(particle, xf, Pf, Q_cov) - - Sfi = np.linalg.inv(Sf) - dz = z[0:2].reshape(2, 1) - zp - dz[1] = pi_2_pi(dz[1]) - - Pi = np.linalg.inv(P) - - particle.P = np.linalg.inv(Hv.T @ Sfi @ Hv + Pi) # proposal covariance - x += particle.P @ Hv.T @ Sfi @ dz # proposal mean - - particle.x = x[0, 0] - particle.y = x[1, 0] - particle.yaw = x[2, 0] - - return particle - - -def update_with_observation(particles, z): - for iz in range(len(z[0, :])): - landmark_id = int(z[2, iz]) - - for ip in range(N_PARTICLE): - # new landmark - if abs(particles[ip].lm[landmark_id, 0]) <= 0.01: - particles[ip] = add_new_lm(particles[ip], z[:, iz], Q) - # known landmark - else: - w = compute_weight(particles[ip], z[:, iz], Q) - particles[ip].w *= w - - particles[ip] = update_landmark(particles[ip], z[:, iz], Q) - particles[ip] = proposal_sampling(particles[ip], z[:, iz], Q) - - return particles - - -def resampling(particles): - """ - low variance re-sampling - """ - - particles = normalize_weight(particles) - - pw = [] - for i in range(N_PARTICLE): - pw.append(particles[i].w) - - pw = np.array(pw) - - n_eff = 1.0 / (pw @ pw.T) # Effective particle number - - if n_eff < NTH: # resampling - w_cum = np.cumsum(pw) - base = np.cumsum(pw * 0.0 + 1 / N_PARTICLE) - 1 / N_PARTICLE - resample_id = base + np.random.rand(base.shape[0]) / N_PARTICLE - - indexes = [] - index = 0 - for ip in range(N_PARTICLE): - while (index < w_cum.shape[0] - 1) \ - and (resample_id[ip] > w_cum[index]): - index += 1 - indexes.append(index) - - tmp_particles = particles[:] - for i in range(len(indexes)): - particles[i].x = tmp_particles[indexes[i]].x - particles[i].y = tmp_particles[indexes[i]].y - particles[i].yaw = tmp_particles[indexes[i]].yaw - particles[i].lm = tmp_particles[indexes[i]].lm[:, :] - particles[i].lmP = tmp_particles[indexes[i]].lmP[:, :] - particles[i].w = 1.0 / N_PARTICLE - - return particles - - -def calc_input(time): - if time <= 3.0: # wait at first - v = 0.0 - yaw_rate = 0.0 - else: - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - - u = np.array([v, yaw_rate]).reshape(2, 1) - - return u - - -def observation(x_true, xd, u, rfid): - # calc true state - x_true = motion_model(x_true, u) - - # add noise to range observation - z = np.zeros((3, 0)) - - for i in range(len(rfid[:, 0])): - - dx = rfid[i, 0] - x_true[0, 0] - dy = rfid[i, 1] - x_true[1, 0] - d = math.hypot(dx, dy) - angle = pi_2_pi(math.atan2(dy, dx) - x_true[2, 0]) - if d <= MAX_RANGE: - dn = d + np.random.randn() * Q_SIM[0, 0] ** 0.5 # add noise - angle_noise = np.random.randn() * Q_SIM[1, 1] ** 0.5 - angle_with_noise = angle + angle_noise # add noise - zi = np.array([dn, pi_2_pi(angle_with_noise), i]).reshape(3, 1) - z = np.hstack((z, zi)) - - # add noise to input - ud1 = u[0, 0] + np.random.randn() * R_SIM[0, 0] ** 0.5 - ud2 = u[1, 0] + np.random.randn() * R_SIM[ - 1, 1] ** 0.5 + OFFSET_YAW_RATE_NOISE - ud = np.array([ud1, ud2]).reshape(2, 1) - - xd = motion_model(xd, ud) - - return x_true, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0], - [0, 1.0, 0], - [0, 0, 1.0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT]]) - - x = F @ x + B @ u - - x[2, 0] = pi_2_pi(x[2, 0]) - - return x - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # RFID positions [x, y] - rfid = np.array([[10.0, -2.0], - [15.0, 10.0], - [15.0, 15.0], - [10.0, 20.0], - [3.0, 15.0], - [-5.0, 20.0], - [-5.0, 5.0], - [-10.0, 15.0] - ]) - n_landmark = rfid.shape[0] - - # State Vector [x y yaw v]' - x_est = np.zeros((STATE_SIZE, 1)) # SLAM estimation - x_true = np.zeros((STATE_SIZE, 1)) # True state - x_dr = np.zeros((STATE_SIZE, 1)) # Dead reckoning - - # history - hist_x_est = x_est - hist_x_true = x_true - hist_x_dr = x_dr - - particles = [Particle(n_landmark) for _ in range(N_PARTICLE)] - - while SIM_TIME >= time: - time += DT - u = calc_input(time) - - x_true, z, x_dr, ud = observation(x_true, x_dr, u, rfid) - - particles = fast_slam2(particles, ud, z) - - x_est = calc_final_state(particles) - - x_state = x_est[0: STATE_SIZE] - - # store data history - hist_x_est = np.hstack((hist_x_est, x_state)) - hist_x_dr = np.hstack((hist_x_dr, x_dr)) - hist_x_true = np.hstack((hist_x_true, x_true)) - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(rfid[:, 0], rfid[:, 1], "*k") - - for iz in range(len(z[:, 0])): - landmark_id = int(z[2, iz]) - plt.plot([x_est[0][0], rfid[landmark_id, 0]], [ - x_est[1][0], rfid[landmark_id, 1]], "-k") - - for i in range(N_PARTICLE): - plt.plot(particles[i].x, particles[i].y, ".r") - plt.plot(particles[i].lm[:, 0], particles[i].lm[:, 1], "xb") - - plt.plot(hist_x_true[0, :], hist_x_true[1, :], "-b") - plt.plot(hist_x_dr[0, :], hist_x_dr[1, :], "-k") - plt.plot(hist_x_est[0, :], hist_x_est[1, :], "-r") - plt.plot(x_est[0], x_est[1], "xk") - plt.axis("equal") - plt.grid(True) - plt.pause(0.001) - - -if __name__ == '__main__': - main() diff --git a/SLAM/GraphBasedSLAM/data/README.rst b/SLAM/GraphBasedSLAM/data/README.rst deleted file mode 100644 index 15bc5b6c03f..00000000000 --- a/SLAM/GraphBasedSLAM/data/README.rst +++ /dev/null @@ -1,6 +0,0 @@ -Acknowledgments and References -============================== - -Thanks to Luca Larlone for allowing inclusion of the `Intel dataset <https://lucacarlone.mit.edu/datasets/>`_ in this repo. - -1. Carlone, L. and Censi, A., 2014. `From angular manifolds to the integer lattice: Guaranteed orientation estimation with application to pose graph optimization <https://arxiv.org/pdf/1211.3063>`_. IEEE Transactions on Robotics, 30(2), pp.475-492. diff --git a/SLAM/GraphBasedSLAM/data/input_INTEL.g2o b/SLAM/GraphBasedSLAM/data/input_INTEL.g2o deleted file mode 100644 index 16f3a2600cb..00000000000 --- a/SLAM/GraphBasedSLAM/data/input_INTEL.g2o +++ /dev/null @@ -1,2711 +0,0 @@ -VERTEX_SE2 0 0.000000 0.000000 0.000000 -VERTEX_SE2 1 0.000000 0.000000 -0.000642 -VERTEX_SE2 2 0.000000 0.000000 -0.001180 -VERTEX_SE2 3 0.011002 -0.000975 -0.003562 -VERTEX_SE2 4 0.641008 -0.011200 -0.007444 -VERTEX_SE2 5 0.696016 -0.011716 -0.098726 -VERTEX_SE2 6 0.700269 -0.015435 -0.895998 -VERTEX_SE2 7 0.693956 0.004213 -1.511535 -VERTEX_SE2 8 0.699263 0.026693 -2.125069 -VERTEX_SE2 9 0.716114 0.041122 -2.763139 -VERTEX_SE2 10 0.728981 0.043219 2.905515 -VERTEX_SE2 11 0.733203 0.040537 2.231236 -VERTEX_SE2 12 0.733186 0.041545 1.581762 -VERTEX_SE2 13 0.738753 0.059070 0.922264 -VERTEX_SE2 14 0.759658 0.073750 0.314025 -VERTEX_SE2 15 0.768572 0.074357 -0.210903 -VERTEX_SE2 16 1.062493 0.014152 -0.229595 -VERTEX_SE2 17 1.663647 -0.133115 -0.260823 -VERTEX_SE2 18 2.287001 -0.296480 -0.271000 -VERTEX_SE2 19 2.914298 -0.494254 -0.319576 -VERTEX_SE2 20 3.527220 -0.693985 -0.308933 -VERTEX_SE2 21 4.152895 -0.850915 -0.191238 -VERTEX_SE2 22 4.779015 -0.992339 -0.168556 -VERTEX_SE2 23 5.423978 -1.030005 -0.054484 -VERTEX_SE2 24 6.064382 -1.090997 -0.105423 -VERTEX_SE2 25 6.707928 -1.144401 -0.096821 -VERTEX_SE2 26 7.315680 -1.224079 -0.137153 -VERTEX_SE2 27 7.929761 -1.294250 -0.121079 -VERTEX_SE2 28 8.510243 -1.372635 -0.125240 -VERTEX_SE2 29 8.886549 -1.416447 -0.094136 -VERTEX_SE2 30 8.893462 -1.418023 -0.625522 -VERTEX_SE2 31 9.005697 -1.557779 -0.893355 -VERTEX_SE2 32 9.398300 -2.067296 -0.911506 -VERTEX_SE2 33 9.800909 -2.566880 -0.858368 -VERTEX_SE2 34 10.230894 -3.045076 -0.834898 -VERTEX_SE2 35 10.670845 -3.512974 -0.797906 -VERTEX_SE2 36 11.118351 -3.980273 -0.803680 -VERTEX_SE2 37 11.413882 -4.282108 -0.793023 -VERTEX_SE2 38 11.416535 -4.285316 -1.109584 -VERTEX_SE2 39 11.425445 -4.316267 -1.276487 -VERTEX_SE2 40 11.612551 -4.916547 -1.255922 -VERTEX_SE2 41 11.808527 -5.541274 -1.284316 -VERTEX_SE2 42 11.976726 -6.133098 -1.303279 -VERTEX_SE2 43 12.132495 -6.760248 -1.339357 -VERTEX_SE2 44 12.273339 -7.389611 -1.372003 -VERTEX_SE2 45 12.381155 -8.023418 -1.427426 -VERTEX_SE2 46 12.464524 -8.661631 -1.446702 -VERTEX_SE2 47 12.536773 -9.300726 -1.488240 -VERTEX_SE2 48 12.585187 -9.946461 -1.494639 -VERTEX_SE2 49 12.629508 -10.588502 -1.545288 -VERTEX_SE2 50 12.623735 -11.202499 -1.589586 -VERTEX_SE2 51 12.613473 -11.816834 -1.619614 -VERTEX_SE2 52 12.558110 -12.427134 -1.697131 -VERTEX_SE2 53 12.497320 -13.013155 -1.685264 -VERTEX_SE2 54 12.418711 -13.557683 -1.747661 -VERTEX_SE2 55 12.419724 -13.549747 -1.742676 -VERTEX_SE2 56 12.414345 -13.580353 -1.732396 -VERTEX_SE2 57 12.310914 -14.233877 -1.743844 -VERTEX_SE2 58 12.203756 -14.876538 -1.697418 -VERTEX_SE2 59 12.115088 -15.515348 -1.720561 -VERTEX_SE2 60 12.025760 -16.150800 -1.698500 -VERTEX_SE2 61 11.930749 -16.787980 -1.748266 -VERTEX_SE2 62 11.833006 -17.390733 -1.709239 -VERTEX_SE2 63 11.733602 -17.998517 -1.746382 -VERTEX_SE2 64 11.649132 -18.607583 -1.685617 -VERTEX_SE2 65 11.563367 -19.214882 -1.740522 -VERTEX_SE2 66 11.460058 -19.848621 -1.752656 -VERTEX_SE2 67 11.343148 -20.481952 -1.756181 -VERTEX_SE2 68 11.257571 -20.955257 -1.774331 -VERTEX_SE2 69 11.255185 -20.964979 -1.932353 -VERTEX_SE2 70 11.251937 -20.972069 -2.613265 -VERTEX_SE2 71 11.258227 -20.971402 3.020985 -VERTEX_SE2 72 11.258227 -20.971402 3.009195 -VERTEX_SE2 73 11.254702 -20.970679 2.941681 -VERTEX_SE2 74 11.251643 -20.968771 2.313797 -VERTEX_SE2 75 11.250298 -20.968291 1.957266 -VERTEX_SE2 76 11.239515 -20.956998 2.644600 -VERTEX_SE2 77 11.227570 -20.952338 2.874132 -VERTEX_SE2 78 10.929861 -20.969392 -3.076000 -VERTEX_SE2 79 10.295660 -21.019100 -3.083625 -VERTEX_SE2 80 9.648073 -21.026221 3.122276 -VERTEX_SE2 81 9.008652 -21.005804 3.093707 -VERTEX_SE2 82 8.367330 -20.952196 3.043418 -VERTEX_SE2 83 7.730227 -20.888698 3.024388 -VERTEX_SE2 84 7.095779 -20.785072 2.952781 -VERTEX_SE2 85 6.465179 -20.660326 2.966718 -VERTEX_SE2 86 5.750805 -20.513125 2.886729 -VERTEX_SE2 87 5.163554 -20.341011 2.848617 -VERTEX_SE2 88 4.815868 -20.234565 2.823505 -VERTEX_SE2 89 4.792324 -20.235107 -3.054605 -VERTEX_SE2 90 4.149209 -20.288628 -3.081395 -VERTEX_SE2 91 3.497178 -20.337577 -3.028289 -VERTEX_SE2 92 2.861629 -20.387679 -3.140035 -VERTEX_SE2 93 2.221011 -20.339858 3.045531 -VERTEX_SE2 94 1.585959 -20.258625 3.005168 -VERTEX_SE2 95 0.940663 -20.228767 -3.139936 -VERTEX_SE2 96 0.302216 -20.232542 -3.119921 -VERTEX_SE2 97 -0.314018 -20.219530 3.087656 -VERTEX_SE2 98 -0.922581 -20.164719 3.024330 -VERTEX_SE2 99 -1.648795 -20.093526 3.065410 -VERTEX_SE2 100 -2.230833 -20.023281 3.007277 -VERTEX_SE2 101 -2.871354 -20.005103 3.102942 -VERTEX_SE2 102 -3.516483 -19.955697 3.008603 -VERTEX_SE2 103 -4.152223 -19.878149 3.115724 -VERTEX_SE2 104 -4.795838 -19.847155 3.090758 -VERTEX_SE2 105 -5.440965 -19.834033 -3.137000 -VERTEX_SE2 106 -6.074366 -19.819256 3.099547 -VERTEX_SE2 107 -6.721384 -19.784913 3.102775 -VERTEX_SE2 108 -7.140409 -19.781530 -3.121388 -VERTEX_SE2 109 -7.153321 -19.779550 2.708464 -VERTEX_SE2 110 -7.164494 -19.769929 2.111343 -VERTEX_SE2 111 -7.174123 -19.662635 1.600354 -VERTEX_SE2 112 -7.201482 -19.000514 1.652438 -VERTEX_SE2 113 -7.269988 -18.356059 1.697296 -VERTEX_SE2 114 -7.351668 -17.722124 1.732079 -VERTEX_SE2 115 -7.477063 -17.090635 1.787906 -VERTEX_SE2 116 -7.655600 -16.348269 1.827325 -VERTEX_SE2 117 -7.838440 -15.740356 1.917383 -VERTEX_SE2 118 -7.847180 -15.710500 1.574139 -VERTEX_SE2 119 -7.822729 -15.211952 1.515457 -VERTEX_SE2 120 -7.806541 -14.573234 1.599604 -VERTEX_SE2 121 -7.846755 -13.965257 1.661084 -VERTEX_SE2 122 -7.908309 -13.357352 1.710992 -VERTEX_SE2 123 -7.944931 -13.145472 1.692222 -VERTEX_SE2 124 -7.867047 -12.909702 1.255856 -VERTEX_SE2 125 -7.662551 -12.318719 1.238631 -VERTEX_SE2 126 -7.536130 -11.694942 1.435606 -VERTEX_SE2 127 -7.446823 -11.065323 1.432524 -VERTEX_SE2 128 -7.378220 -10.424022 1.466677 -VERTEX_SE2 129 -7.297629 -9.790420 1.431058 -VERTEX_SE2 130 -7.233612 -9.152396 1.479951 -VERTEX_SE2 131 -7.188908 -8.512333 1.563552 -VERTEX_SE2 132 -7.169731 -7.871150 1.508512 -VERTEX_SE2 133 -7.117635 -7.291335 1.466418 -VERTEX_SE2 134 -7.055851 -6.684237 1.442294 -VERTEX_SE2 135 -6.963757 -6.111663 1.409225 -VERTEX_SE2 136 -6.874804 -5.474955 1.421265 -VERTEX_SE2 137 -6.760504 -4.850881 1.369865 -VERTEX_SE2 138 -6.660597 -4.217332 1.438397 -VERTEX_SE2 139 -6.600415 -3.595492 1.503413 -VERTEX_SE2 140 -6.582744 -2.945853 1.533669 -VERTEX_SE2 141 -6.543894 -2.313106 1.484948 -VERTEX_SE2 142 -6.498552 -1.671107 1.480848 -VERTEX_SE2 143 -6.373361 -1.045821 1.369956 -VERTEX_SE2 144 -6.308206 -0.684059 1.387205 -VERTEX_SE2 145 -6.303725 -0.673188 0.888171 -VERTEX_SE2 146 -6.303130 -0.671010 0.294225 -VERTEX_SE2 147 -6.246280 -0.679152 -0.192923 -VERTEX_SE2 148 -5.818303 -0.770932 -0.228866 -VERTEX_SE2 149 -5.184464 -0.911850 -0.204032 -VERTEX_SE2 150 -4.555178 -1.023116 -0.190122 -VERTEX_SE2 151 -3.919217 -1.117808 -0.104723 -VERTEX_SE2 152 -3.282062 -1.199418 -0.172903 -VERTEX_SE2 153 -2.645312 -1.282994 -0.087181 -VERTEX_SE2 154 -2.011150 -1.359207 -0.164419 -VERTEX_SE2 155 -1.375820 -1.453297 -0.137992 -VERTEX_SE2 156 -0.735790 -1.532677 -0.114327 -VERTEX_SE2 157 -0.159947 -1.613323 -0.186690 -VERTEX_SE2 158 0.023851 -1.648467 -0.157600 -VERTEX_SE2 159 0.021228 -1.647288 0.835817 -VERTEX_SE2 160 0.027488 -1.639228 1.877886 -VERTEX_SE2 161 0.027486 -1.639234 2.859828 -VERTEX_SE2 162 0.045975 -1.631965 -2.381155 -VERTEX_SE2 163 0.045893 -1.634205 -1.377922 -VERTEX_SE2 164 0.057499 -1.646265 -0.447964 -VERTEX_SE2 165 0.193934 -1.655710 -0.045831 -VERTEX_SE2 166 0.853469 -1.682017 -0.046800 -VERTEX_SE2 167 1.490484 -1.716964 -0.075973 -VERTEX_SE2 168 2.098800 -1.751671 -0.063936 -VERTEX_SE2 169 2.712806 -1.808931 -0.100989 -VERTEX_SE2 170 3.318192 -1.863258 -0.121905 -VERTEX_SE2 171 3.896234 -1.949098 -0.160646 -VERTEX_SE2 172 4.538410 -2.042425 -0.147172 -VERTEX_SE2 173 5.172424 -2.149723 -0.165214 -VERTEX_SE2 174 5.803089 -2.247662 -0.120052 -VERTEX_SE2 175 6.424807 -2.318550 -0.139998 -VERTEX_SE2 176 7.030678 -2.417232 -0.125711 -VERTEX_SE2 177 7.660479 -2.494551 -0.148623 -VERTEX_SE2 178 8.290147 -2.612123 -0.182806 -VERTEX_SE2 179 8.639509 -2.668503 -0.129585 -VERTEX_SE2 180 8.642601 -2.669171 -0.571750 -VERTEX_SE2 181 9.107062 -2.977761 -0.623138 -VERTEX_SE2 182 9.551340 -3.341562 -0.796106 -VERTEX_SE2 183 9.953562 -3.792478 -0.852123 -VERTEX_SE2 184 10.330878 -4.306658 -1.002936 -VERTEX_SE2 185 10.652963 -4.854256 -1.099221 -VERTEX_SE2 186 10.909459 -5.445570 -1.168989 -VERTEX_SE2 187 11.138453 -6.018162 -1.194573 -VERTEX_SE2 188 11.372847 -6.610777 -1.202696 -VERTEX_SE2 189 11.598101 -7.209159 -1.232095 -VERTEX_SE2 190 11.795596 -7.819838 -1.258284 -VERTEX_SE2 191 11.984938 -8.432395 -1.279246 -VERTEX_SE2 192 12.158054 -9.043198 -1.303901 -VERTEX_SE2 193 12.302583 -9.611434 -1.355161 -VERTEX_SE2 194 12.426909 -10.210284 -1.377141 -VERTEX_SE2 195 12.534319 -10.811416 -1.400368 -VERTEX_SE2 196 12.632338 -11.445843 -1.442220 -VERTEX_SE2 197 12.700713 -12.082422 -1.470453 -VERTEX_SE2 198 12.755597 -12.719166 -1.529113 -VERTEX_SE2 199 12.754761 -13.356843 -1.590711 -VERTEX_SE2 200 12.733560 -13.993458 -1.612475 -VERTEX_SE2 201 12.687026 -14.631689 -1.668718 -VERTEX_SE2 202 12.639077 -15.202899 -1.651577 -VERTEX_SE2 203 12.556158 -16.006543 -1.707054 -VERTEX_SE2 204 12.455302 -16.598850 -1.804142 -VERTEX_SE2 205 12.305924 -17.187841 -1.809172 -VERTEX_SE2 206 12.174405 -17.760149 -1.802549 -VERTEX_SE2 207 12.040676 -18.353284 -1.781423 -VERTEX_SE2 208 11.897670 -18.981299 -1.785518 -VERTEX_SE2 209 11.769917 -19.609340 -1.741125 -VERTEX_SE2 210 11.647398 -20.238835 -1.754048 -VERTEX_SE2 211 11.537207 -20.870318 -1.755716 -VERTEX_SE2 212 11.394970 -21.493361 -1.812926 -VERTEX_SE2 213 11.230953 -22.120731 -1.837752 -VERTEX_SE2 214 11.058372 -22.734177 -1.845436 -VERTEX_SE2 215 10.953834 -23.088866 -1.885350 -VERTEX_SE2 216 10.950554 -23.095138 -2.393113 -VERTEX_SE2 217 10.952753 -23.094815 -2.944927 -VERTEX_SE2 218 10.951809 -23.094487 -3.005204 -VERTEX_SE2 219 10.365803 -23.067344 3.104107 -VERTEX_SE2 220 9.737327 -23.038247 3.059963 -VERTEX_SE2 221 9.095837 -22.994717 3.111718 -VERTEX_SE2 222 8.460944 -22.975047 3.086737 -VERTEX_SE2 223 7.821250 -22.969336 -3.100192 -VERTEX_SE2 224 7.183803 -22.994444 -3.126677 -VERTEX_SE2 225 6.544582 -23.012637 -3.078368 -VERTEX_SE2 226 5.906305 -23.029186 -3.129535 -VERTEX_SE2 227 5.264179 -23.084344 -2.972817 -VERTEX_SE2 228 4.660809 -23.049652 2.951621 -VERTEX_SE2 229 4.059169 -22.969281 3.076549 -VERTEX_SE2 230 3.689211 -22.947652 3.051106 -VERTEX_SE2 231 3.819912 -22.954624 3.124109 -VERTEX_SE2 232 3.476990 -22.813142 2.710350 -VERTEX_SE2 233 2.875321 -22.565879 2.819555 -VERTEX_SE2 234 2.261463 -22.358960 2.781360 -VERTEX_SE2 235 1.979653 -22.255530 2.781875 -VERTEX_SE2 236 1.616344 -22.278805 -3.083673 -VERTEX_SE2 237 0.964219 -22.341873 -3.006771 -VERTEX_SE2 238 0.323899 -22.443278 -3.033605 -VERTEX_SE2 239 -0.317791 -22.494927 -3.094849 -VERTEX_SE2 240 -0.925503 -22.426348 2.978831 -VERTEX_SE2 241 -1.504549 -22.345735 3.071089 -VERTEX_SE2 242 -2.117312 -22.325210 3.098446 -VERTEX_SE2 243 -2.764025 -22.279874 3.087887 -VERTEX_SE2 244 -3.406724 -22.271623 -3.133223 -VERTEX_SE2 245 -4.041131 -22.254659 3.087973 -VERTEX_SE2 246 -4.684337 -22.191483 3.008717 -VERTEX_SE2 247 -5.325218 -22.128855 3.108731 -VERTEX_SE2 248 -5.890123 -22.137360 3.133698 -VERTEX_SE2 249 -5.854210 -22.141017 -2.965499 -VERTEX_SE2 250 -5.862024 -22.141342 2.710834 -VERTEX_SE2 251 -6.210340 -21.788237 2.273028 -VERTEX_SE2 252 -6.584399 -21.351579 2.275461 -VERTEX_SE2 253 -6.971866 -20.886741 2.258217 -VERTEX_SE2 254 -7.349642 -20.406697 2.210371 -VERTEX_SE2 255 -7.376562 -20.371386 2.285362 -VERTEX_SE2 256 -7.376569 -20.370011 1.785796 -VERTEX_SE2 257 -7.435125 -19.813876 1.686629 -VERTEX_SE2 258 -7.526140 -19.190499 1.778261 -VERTEX_SE2 259 -7.676213 -18.571996 1.817167 -VERTEX_SE2 260 -7.815262 -17.997419 1.807084 -VERTEX_SE2 261 -7.812802 -17.957528 1.492756 -VERTEX_SE2 262 -7.748761 -17.305023 1.497634 -VERTEX_SE2 263 -7.704459 -16.684761 1.509160 -VERTEX_SE2 264 -7.686285 -16.075835 1.603801 -VERTEX_SE2 265 -7.713685 -15.464092 1.621756 -VERTEX_SE2 266 -7.659836 -14.884512 1.489698 -VERTEX_SE2 267 -7.590637 -14.130213 1.451229 -VERTEX_SE2 268 -7.434892 -13.512524 1.330524 -VERTEX_SE2 269 -7.285843 -12.888133 1.352351 -VERTEX_SE2 270 -7.181145 -12.258185 1.457078 -VERTEX_SE2 271 -7.046662 -11.629374 1.337392 -VERTEX_SE2 272 -6.916330 -10.998172 1.394889 -VERTEX_SE2 273 -6.887272 -10.359052 1.601643 -VERTEX_SE2 274 -6.914937 -9.718617 1.621477 -VERTEX_SE2 275 -6.859410 -9.108548 1.443918 -VERTEX_SE2 276 -6.805341 -8.498288 1.552614 -VERTEX_SE2 277 -6.805090 -7.914615 1.521694 -VERTEX_SE2 278 -6.706035 -7.282637 1.426405 -VERTEX_SE2 279 -6.600956 -6.648396 1.372248 -VERTEX_SE2 280 -6.468990 -6.023366 1.375327 -VERTEX_SE2 281 -6.315271 -5.399485 1.276051 -VERTEX_SE2 282 -6.134008 -4.785899 1.316907 -VERTEX_SE2 283 -5.985222 -4.161193 1.309959 -VERTEX_SE2 284 -5.813249 -3.550243 1.337990 -VERTEX_SE2 285 -5.683475 -2.918967 1.354789 -VERTEX_SE2 286 -5.554450 -2.315719 1.403911 -VERTEX_SE2 287 -5.547714 -2.274662 1.294491 -VERTEX_SE2 288 -5.541900 -2.266525 0.674528 -VERTEX_SE2 289 -5.522271 -2.259034 0.069939 -VERTEX_SE2 290 -5.061939 -2.331133 -0.161343 -VERTEX_SE2 291 -4.422087 -2.430958 -0.151620 -VERTEX_SE2 292 -3.797538 -2.541567 -0.206901 -VERTEX_SE2 293 -3.169915 -2.679421 -0.230678 -VERTEX_SE2 294 -2.547430 -2.824259 -0.230786 -VERTEX_SE2 295 -1.930374 -2.997710 -0.344395 -VERTEX_SE2 296 -1.332265 -3.234619 -0.390911 -VERTEX_SE2 297 -0.738078 -3.478649 -0.403774 -VERTEX_SE2 298 -0.140714 -3.729757 -0.400411 -VERTEX_SE2 299 0.420679 -3.975672 -0.334750 -VERTEX_SE2 300 1.008544 -4.149557 -0.288323 -VERTEX_SE2 301 1.570135 -4.331714 -0.343252 -VERTEX_SE2 302 1.877809 -4.442855 -0.360266 -VERTEX_SE2 303 1.877809 -4.442855 -0.352308 -VERTEX_SE2 304 2.376686 -4.626875 -0.338959 -VERTEX_SE2 305 3.003258 -4.750507 -0.149877 -VERTEX_SE2 306 3.635522 -4.836601 -0.164412 -VERTEX_SE2 307 4.273138 -4.958970 -0.197471 -VERTEX_SE2 308 4.897872 -5.092864 -0.249303 -VERTEX_SE2 309 5.530724 -5.222563 -0.152307 -VERTEX_SE2 310 6.160264 -5.318301 -0.184629 -VERTEX_SE2 311 6.445365 -5.373694 -0.004883 -VERTEX_SE2 312 6.452735 -5.370466 0.998034 -VERTEX_SE2 313 6.475194 -5.146827 1.501717 -VERTEX_SE2 314 6.500598 -4.513221 1.545236 -VERTEX_SE2 315 6.514519 -3.879666 1.544361 -VERTEX_SE2 316 6.515603 -3.240166 1.596992 -VERTEX_SE2 317 6.494598 -2.602753 1.608134 -VERTEX_SE2 318 6.435460 -1.967773 1.704091 -VERTEX_SE2 319 6.377663 -1.623559 1.776803 -VERTEX_SE2 320 6.378012 -1.622652 2.750031 -VERTEX_SE2 321 6.369361 -1.625849 -2.488361 -VERTEX_SE2 322 6.365946 -1.632038 -1.487277 -VERTEX_SE2 323 6.380435 -1.647235 -0.490000 -VERTEX_SE2 324 6.388880 -1.650346 0.173199 -VERTEX_SE2 325 6.392046 -1.650203 -0.351692 -VERTEX_SE2 326 6.411655 -1.665878 -0.943866 -VERTEX_SE2 327 6.415870 -1.688728 -1.564092 -VERTEX_SE2 328 6.385292 -2.332605 -1.609333 -VERTEX_SE2 329 6.349431 -2.981039 -1.664005 -VERTEX_SE2 330 6.281461 -3.617106 -1.682877 -VERTEX_SE2 331 6.213453 -4.254537 -1.697056 -VERTEX_SE2 332 6.121245 -4.888223 -1.715483 -VERTEX_SE2 333 6.093922 -5.063750 -1.650313 -VERTEX_SE2 334 6.091827 -5.064491 -0.592795 -VERTEX_SE2 335 6.120861 -5.065606 0.404271 -VERTEX_SE2 336 6.129696 -5.059618 1.351179 -VERTEX_SE2 337 6.128718 -5.050440 2.336187 -VERTEX_SE2 338 6.132587 -5.051833 -2.965274 -VERTEX_SE2 339 6.136968 -5.047185 -1.923597 -VERTEX_SE2 340 6.142971 -5.060659 -0.911817 -VERTEX_SE2 341 6.275970 -5.101488 -0.283246 -VERTEX_SE2 342 6.910811 -5.263299 -0.183431 -VERTEX_SE2 343 7.538989 -5.324161 -0.052630 -VERTEX_SE2 344 8.173624 -5.364758 -0.062705 -VERTEX_SE2 345 8.440897 -5.378047 -0.090243 -VERTEX_SE2 346 8.445372 -5.378415 -0.737666 -VERTEX_SE2 347 8.467770 -5.462068 -1.296495 -VERTEX_SE2 348 8.621467 -6.030776 -1.313338 -VERTEX_SE2 349 8.761762 -6.631679 -1.353796 -VERTEX_SE2 350 8.929986 -7.398958 -1.373714 -VERTEX_SE2 351 8.978041 -7.665351 -1.403006 -VERTEX_SE2 352 8.978090 -7.667619 -1.691302 -VERTEX_SE2 353 8.976498 -7.670853 -2.356727 -VERTEX_SE2 354 8.981756 -7.667962 -2.960124 -VERTEX_SE2 355 8.981756 -7.667962 2.602071 -VERTEX_SE2 356 8.978992 -7.664902 2.026818 -VERTEX_SE2 357 8.977837 -7.643021 1.373746 -VERTEX_SE2 358 8.983884 -7.628618 0.758292 -VERTEX_SE2 359 8.989631 -7.624545 0.144263 -VERTEX_SE2 360 8.994126 -7.624478 -0.032038 -VERTEX_SE2 361 9.004896 -7.619118 0.887338 -VERTEX_SE2 362 9.042246 -7.366063 1.421081 -VERTEX_SE2 363 9.090049 -7.072841 1.414605 -VERTEX_SE2 364 8.954880 -6.758641 2.029221 -VERTEX_SE2 365 8.843129 -6.487231 1.532139 -VERTEX_SE2 366 8.933049 -6.331605 0.978068 -VERTEX_SE2 367 9.294391 -5.803956 0.980155 -VERTEX_SE2 368 9.641307 -5.309201 0.927211 -VERTEX_SE2 369 9.642383 -5.307246 0.668025 -VERTEX_SE2 370 9.648356 -5.305144 0.068704 -VERTEX_SE2 371 9.655229 -5.307316 -0.488502 -VERTEX_SE2 372 10.139103 -5.587085 -0.520850 -VERTEX_SE2 373 10.666751 -5.878088 -0.523177 -VERTEX_SE2 374 11.206068 -6.209159 -0.589126 -VERTEX_SE2 375 11.598593 -6.466633 -0.617897 -VERTEX_SE2 376 11.600632 -6.467490 0.080627 -VERTEX_SE2 377 11.643620 -6.425565 0.779646 -VERTEX_SE2 378 12.107190 -5.948151 0.834726 -VERTEX_SE2 379 12.510240 -5.446009 0.920455 -VERTEX_SE2 380 12.867606 -4.912917 1.040753 -VERTEX_SE2 381 12.982544 -4.709680 1.191659 -VERTEX_SE2 382 12.984649 -4.703709 2.244782 -VERTEX_SE2 383 12.988448 -4.705226 -3.058347 -VERTEX_SE2 384 12.986650 -4.707628 -2.101256 -VERTEX_SE2 385 12.982495 -4.718256 -1.078274 -VERTEX_SE2 386 13.111397 -4.840399 -0.855882 -VERTEX_SE2 387 13.631915 -5.191372 -0.527133 -VERTEX_SE2 388 14.188298 -5.499440 -0.516375 -VERTEX_SE2 389 14.722428 -5.830510 -0.596695 -VERTEX_SE2 390 14.780394 -5.868314 -0.117993 -VERTEX_SE2 391 14.643686 -5.885580 0.265004 -VERTEX_SE2 392 14.640989 -5.886114 1.312766 -VERTEX_SE2 393 14.635188 -5.855400 2.572219 -VERTEX_SE2 394 14.626068 -5.853862 -2.712409 -VERTEX_SE2 395 14.810464 -5.693039 -2.372812 -VERTEX_SE2 396 14.810464 -5.693039 -2.371562 -VERTEX_SE2 397 14.809202 -5.693678 -2.381203 -VERTEX_SE2 398 14.806796 -5.697007 -2.182098 -VERTEX_SE2 399 14.762364 -5.814932 -1.881357 -VERTEX_SE2 400 14.564819 -6.441727 -1.829942 -VERTEX_SE2 401 14.377600 -7.049960 -1.921842 -VERTEX_SE2 402 14.049396 -7.600148 -2.188305 -VERTEX_SE2 403 13.678588 -8.113304 -2.221999 -VERTEX_SE2 404 13.306297 -8.574268 -2.300702 -VERTEX_SE2 405 13.304585 -8.576945 -1.766179 -VERTEX_SE2 406 13.302371 -8.571544 -0.786819 -VERTEX_SE2 407 13.585994 -8.797369 -0.658504 -VERTEX_SE2 408 14.069560 -9.180165 -0.696311 -VERTEX_SE2 409 14.292699 -9.377696 -0.795739 -VERTEX_SE2 410 14.294947 -9.381536 -1.423249 -VERTEX_SE2 411 14.294896 -9.380539 -2.012202 -VERTEX_SE2 412 13.969601 -9.830799 -2.215053 -VERTEX_SE2 413 13.573781 -10.323212 -2.294584 -VERTEX_SE2 414 13.168212 -10.809845 -2.190851 -VERTEX_SE2 415 12.788348 -11.328437 -2.184168 -VERTEX_SE2 416 12.618672 -11.583273 -2.239720 -VERTEX_SE2 417 12.365589 -11.724804 -2.664770 -VERTEX_SE2 418 11.973570 -11.921372 -2.710238 -VERTEX_SE2 419 11.979618 -11.915306 -2.279799 -VERTEX_SE2 420 12.016291 -11.860711 -2.064037 -VERTEX_SE2 421 12.016287 -11.845604 -1.097383 -VERTEX_SE2 422 12.016575 -11.841230 0.140539 -VERTEX_SE2 423 12.021144 -11.838978 0.485675 -VERTEX_SE2 424 12.021144 -11.838978 0.485954 -VERTEX_SE2 425 12.020459 -11.840215 0.497589 -VERTEX_SE2 426 12.020459 -11.840215 0.488372 -VERTEX_SE2 427 12.049082 -11.824671 0.491399 -VERTEX_SE2 428 12.625045 -11.496891 0.485740 -VERTEX_SE2 429 13.200413 -11.202813 0.444713 -VERTEX_SE2 430 13.512701 -11.059854 0.398340 -VERTEX_SE2 431 13.491669 -11.069431 0.449977 -VERTEX_SE2 432 13.501654 -11.067336 -0.182740 -VERTEX_SE2 433 13.502954 -11.067884 -0.861102 -VERTEX_SE2 434 13.743529 -11.537644 -1.089862 -VERTEX_SE2 435 14.040604 -12.094609 -1.118566 -VERTEX_SE2 436 14.297216 -12.672347 -1.127731 -VERTEX_SE2 437 14.580075 -13.245886 -1.120167 -VERTEX_SE2 438 14.774602 -13.672697 -1.152842 -VERTEX_SE2 439 14.775466 -13.675785 -1.592980 -VERTEX_SE2 440 14.781226 -13.661057 -2.241615 -VERTEX_SE2 441 14.801541 -13.646476 -2.868987 -VERTEX_SE2 442 14.816809 -13.646193 2.779417 -VERTEX_SE2 443 14.817345 -13.647038 2.207553 -VERTEX_SE2 444 14.811569 -13.629249 1.610879 -VERTEX_SE2 445 14.815891 -13.615770 0.947107 -VERTEX_SE2 446 14.818888 -13.610711 1.145697 -VERTEX_SE2 447 14.818661 -13.580487 1.771810 -VERTEX_SE2 448 14.666760 -12.956104 1.786852 -VERTEX_SE2 449 14.494693 -12.326428 1.885308 -VERTEX_SE2 450 14.289690 -11.713731 1.896557 -VERTEX_SE2 451 14.124257 -11.267884 1.936509 -VERTEX_SE2 452 14.123115 -11.264972 1.553661 -VERTEX_SE2 453 14.123047 -11.266384 0.924731 -VERTEX_SE2 454 14.355665 -11.130372 0.497531 -VERTEX_SE2 455 14.885259 -10.850245 0.477764 -VERTEX_SE2 456 15.454443 -10.572873 0.414138 -VERTEX_SE2 457 15.786015 -10.438633 0.327481 -VERTEX_SE2 458 15.795226 -10.438701 -0.315965 -VERTEX_SE2 459 15.791330 -10.434037 -0.921822 -VERTEX_SE2 460 15.959734 -10.828507 -1.177398 -VERTEX_SE2 461 16.180144 -11.439953 -1.264281 -VERTEX_SE2 462 16.335308 -11.963645 -1.303337 -VERTEX_SE2 463 16.335291 -11.965068 -0.460067 -VERTEX_SE2 464 16.605696 -11.914838 0.220623 -VERTEX_SE2 465 17.195283 -11.771695 0.229379 -VERTEX_SE2 466 17.767104 -11.657874 0.174926 -VERTEX_SE2 467 18.369280 -11.563197 0.132707 -VERTEX_SE2 468 19.009735 -11.482106 0.096378 -VERTEX_SE2 469 19.650896 -11.453733 0.012587 -VERTEX_SE2 470 20.146853 -11.442829 0.030741 -VERTEX_SE2 471 20.150029 -11.442932 -0.170062 -VERTEX_SE2 472 20.172311 -11.454699 -0.804400 -VERTEX_SE2 473 20.175889 -11.459298 -1.446679 -VERTEX_SE2 474 20.174399 -11.466191 -2.079685 -VERTEX_SE2 475 20.170246 -11.468957 -2.655668 -VERTEX_SE2 476 20.165497 -11.470500 2.973880 -VERTEX_SE2 477 20.170525 -11.474309 2.412190 -VERTEX_SE2 478 20.175145 -11.482300 1.782778 -VERTEX_SE2 479 20.175335 -11.487697 1.326596 -VERTEX_SE2 480 20.175383 -11.489918 1.886460 -VERTEX_SE2 481 20.164295 -11.475887 2.884919 -VERTEX_SE2 482 20.162062 -11.476008 -3.063751 -VERTEX_SE2 483 20.162062 -11.476008 -3.070064 -VERTEX_SE2 484 19.701970 -11.512371 -3.035533 -VERTEX_SE2 485 19.076677 -11.593317 -3.038332 -VERTEX_SE2 486 18.439371 -11.653164 -3.029341 -VERTEX_SE2 487 17.807280 -11.746714 -3.001669 -VERTEX_SE2 488 17.172291 -11.839127 -2.966212 -VERTEX_SE2 489 16.696147 -11.938931 -2.936476 -VERTEX_SE2 490 16.692490 -11.941051 -2.452793 -VERTEX_SE2 491 16.691616 -11.944932 -1.519098 -VERTEX_SE2 492 16.776617 -12.175290 -1.217149 -VERTEX_SE2 493 16.974062 -12.765556 -1.272900 -VERTEX_SE2 494 17.150447 -13.373462 -1.334510 -VERTEX_SE2 495 17.352115 -13.978346 -1.223707 -VERTEX_SE2 496 17.581624 -14.577196 -1.102707 -VERTEX_SE2 497 17.847299 -15.159575 -1.186084 -VERTEX_SE2 498 18.054425 -15.760767 -1.285551 -VERTEX_SE2 499 18.205483 -16.382164 -1.300921 -VERTEX_SE2 500 18.520086 -16.898620 -0.969638 -VERTEX_SE2 501 18.848430 -17.411482 -1.035455 -VERTEX_SE2 502 19.181866 -18.047877 -1.113614 -VERTEX_SE2 503 19.382829 -18.470616 -1.125142 -VERTEX_SE2 504 19.382968 -18.471669 -0.242877 -VERTEX_SE2 505 19.636847 -18.373822 0.396037 -VERTEX_SE2 506 20.222463 -18.152233 0.250781 -VERTEX_SE2 507 20.842906 -18.012083 0.178603 -VERTEX_SE2 508 21.473389 -17.912172 0.170945 -VERTEX_SE2 509 22.107555 -17.811551 0.119274 -VERTEX_SE2 510 22.477732 -17.773275 0.109324 -VERTEX_SE2 511 22.480191 -17.776579 1.000327 -VERTEX_SE2 512 22.479151 -17.767197 2.221724 -VERTEX_SE2 513 22.480923 -17.768589 -3.088724 -VERTEX_SE2 514 22.392210 -17.797083 -2.856452 -VERTEX_SE2 515 21.763760 -17.994866 -2.851524 -VERTEX_SE2 516 21.150540 -18.168893 -2.831780 -VERTEX_SE2 517 20.555780 -18.389856 -2.799728 -VERTEX_SE2 518 19.960512 -18.610158 -2.771638 -VERTEX_SE2 519 19.439217 -18.815169 -2.783788 -VERTEX_SE2 520 19.254408 -18.883689 -2.378354 -VERTEX_SE2 521 19.253544 -18.891468 -1.358862 -VERTEX_SE2 522 19.446557 -19.274210 -1.088837 -VERTEX_SE2 523 19.743533 -19.846628 -1.102099 -VERTEX_SE2 524 20.002482 -20.395419 -1.149751 -VERTEX_SE2 525 20.240546 -20.920829 -1.130979 -VERTEX_SE2 526 20.481533 -21.478440 -1.194565 -VERTEX_SE2 527 20.701007 -22.071838 -1.233424 -VERTEX_SE2 528 20.883349 -22.686071 -1.313266 -VERTEX_SE2 529 21.048790 -23.294125 -1.338785 -VERTEX_SE2 530 21.186548 -23.922294 -1.365903 -VERTEX_SE2 531 21.294513 -24.545568 -1.442267 -VERTEX_SE2 532 21.321981 -24.753969 -1.388289 -VERTEX_SE2 533 21.331696 -24.762834 -0.381514 -VERTEX_SE2 534 21.336665 -24.762597 0.290307 -VERTEX_SE2 535 21.336665 -24.762597 0.291645 -VERTEX_SE2 536 21.667408 -24.621679 0.424610 -VERTEX_SE2 537 22.237616 -24.383793 0.368660 -VERTEX_SE2 538 22.783578 -24.188298 0.343558 -VERTEX_SE2 539 23.392496 -23.994630 0.281055 -VERTEX_SE2 540 24.012651 -23.846863 0.190656 -VERTEX_SE2 541 24.616500 -23.677520 0.355935 -VERTEX_SE2 542 25.198874 -23.413487 0.414186 -VERTEX_SE2 543 25.308230 -23.366534 0.386937 -VERTEX_SE2 544 25.311458 -23.363477 1.030295 -VERTEX_SE2 545 25.308953 -23.348021 2.106974 -VERTEX_SE2 546 25.370099 -23.384281 2.942044 -VERTEX_SE2 547 25.364196 -23.389842 -2.309543 -VERTEX_SE2 548 25.360603 -23.401304 -1.377667 -VERTEX_SE2 549 25.371198 -23.418104 -0.563163 -VERTEX_SE2 550 25.376228 -23.423323 -1.037842 -VERTEX_SE2 551 25.379648 -23.436304 -1.657979 -VERTEX_SE2 552 25.377719 -23.441024 -2.284180 -VERTEX_SE2 553 25.238021 -23.493388 -2.855731 -VERTEX_SE2 554 24.607784 -23.677279 -2.888859 -VERTEX_SE2 555 23.993431 -23.860841 -2.797492 -VERTEX_SE2 556 23.396241 -24.105763 -2.659796 -VERTEX_SE2 557 22.822728 -24.393516 -2.702744 -VERTEX_SE2 558 22.275040 -24.674698 -2.623823 -VERTEX_SE2 559 22.270077 -24.676821 -3.034381 -VERTEX_SE2 560 22.270077 -24.676821 2.743761 -VERTEX_SE2 561 22.260080 -24.676351 -3.038320 -VERTEX_SE2 562 22.096754 -24.820650 -2.399936 -VERTEX_SE2 563 21.592502 -25.154311 -2.594747 -VERTEX_SE2 564 21.053412 -25.498706 -2.548499 -VERTEX_SE2 565 20.537425 -25.832798 -2.600465 -VERTEX_SE2 566 20.532490 -25.835035 -1.796294 -VERTEX_SE2 567 20.533426 -25.833987 -0.940208 -VERTEX_SE2 568 20.891388 -26.294540 -0.894012 -VERTEX_SE2 569 21.276856 -26.790552 -0.946159 -VERTEX_SE2 570 21.649420 -27.310717 -0.950967 -VERTEX_SE2 571 21.849361 -27.596250 -0.994364 -VERTEX_SE2 572 21.840333 -27.646492 -1.231717 -VERTEX_SE2 573 21.868880 -27.724009 -0.949072 -VERTEX_SE2 574 21.877216 -27.725452 0.006744 -VERTEX_SE2 575 21.894503 -27.715687 1.016050 -VERTEX_SE2 576 21.893519 -27.715892 2.040189 -VERTEX_SE2 577 21.885895 -27.713246 3.008947 -VERTEX_SE2 578 21.866274 -27.704702 2.643177 -VERTEX_SE2 579 21.298924 -27.387881 2.657278 -VERTEX_SE2 580 20.716909 -27.105551 2.731333 -VERTEX_SE2 581 20.125767 -26.856860 2.772637 -VERTEX_SE2 582 19.523535 -26.633599 2.814640 -VERTEX_SE2 583 19.213810 -26.536403 2.892766 -VERTEX_SE2 584 19.210319 -26.535584 -2.550218 -VERTEX_SE2 585 18.716874 -26.893765 -2.433208 -VERTEX_SE2 586 18.264978 -27.304159 -2.336932 -VERTEX_SE2 587 17.844050 -27.776684 -2.312675 -VERTEX_SE2 588 17.404102 -28.246717 -2.309353 -VERTEX_SE2 589 17.007668 -28.742973 -2.229083 -VERTEX_SE2 590 16.625023 -29.262060 -2.155304 -VERTEX_SE2 591 16.286319 -29.796280 -2.152683 -VERTEX_SE2 592 15.939159 -30.336565 -2.150686 -VERTEX_SE2 593 15.791190 -30.564791 -1.938181 -VERTEX_SE2 594 15.794250 -30.581455 -0.945084 -VERTEX_SE2 595 16.194292 -30.997078 -0.704760 -VERTEX_SE2 596 16.636104 -31.366417 -0.722635 -VERTEX_SE2 597 17.103989 -31.796447 -0.756770 -VERTEX_SE2 598 17.538795 -32.215917 -0.796372 -VERTEX_SE2 599 17.800839 -32.499098 -0.859831 -VERTEX_SE2 600 17.808423 -32.504032 -0.045074 -VERTEX_SE2 601 17.830600 -32.493623 0.983541 -VERTEX_SE2 602 17.834247 -32.474305 2.007952 -VERTEX_SE2 603 17.607884 -32.374428 2.788384 -VERTEX_SE2 604 17.046943 -32.100473 2.547892 -VERTEX_SE2 605 16.511286 -31.761753 2.630512 -VERTEX_SE2 606 15.949994 -31.464096 2.672598 -VERTEX_SE2 607 15.464785 -31.153778 2.591564 -VERTEX_SE2 608 15.140800 -30.969820 2.636022 -VERTEX_SE2 609 15.131468 -30.966068 2.972317 -VERTEX_SE2 610 15.122044 -30.973580 -2.378251 -VERTEX_SE2 611 14.678938 -31.406105 -2.375287 -VERTEX_SE2 612 14.313602 -31.741587 -2.372510 -VERTEX_SE2 613 14.338061 -31.720011 -1.908805 -VERTEX_SE2 614 14.338698 -31.726674 -0.870968 -VERTEX_SE2 615 14.768768 -31.977559 -0.566453 -VERTEX_SE2 616 15.311642 -32.305648 -0.617609 -VERTEX_SE2 617 15.760313 -32.746217 -0.834639 -VERTEX_SE2 618 16.193436 -33.214065 -0.824521 -VERTEX_SE2 619 16.601337 -33.656810 -0.825989 -VERTEX_SE2 620 17.000072 -34.120401 -0.922318 -VERTEX_SE2 621 16.788426 -33.839458 -0.973924 -VERTEX_SE2 622 16.630958 -33.597689 -1.048966 -VERTEX_SE2 623 16.629619 -33.594321 -1.586115 -VERTEX_SE2 624 16.631309 -33.591662 -2.228805 -VERTEX_SE2 625 16.624999 -33.596266 -2.887438 -VERTEX_SE2 626 16.617480 -33.597475 2.777619 -VERTEX_SE2 627 16.349285 -33.346497 2.366813 -VERTEX_SE2 628 15.919513 -32.868045 2.265896 -VERTEX_SE2 629 15.485805 -32.395397 2.336946 -VERTEX_SE2 630 15.046318 -31.973583 2.422035 -VERTEX_SE2 631 14.646636 -31.639639 2.442255 -VERTEX_SE2 632 14.643929 -31.637238 3.118464 -VERTEX_SE2 633 14.589597 -31.712326 -2.089116 -VERTEX_SE2 634 14.266192 -32.277649 -2.063889 -VERTEX_SE2 635 13.925936 -32.819825 -2.201180 -VERTEX_SE2 636 13.554818 -33.335756 -2.220264 -VERTEX_SE2 637 13.147645 -33.820778 -2.320948 -VERTEX_SE2 638 12.855265 -34.121161 -2.351695 -VERTEX_SE2 639 12.424371 -34.596136 -2.272930 -VERTEX_SE2 640 11.985578 -35.070016 -2.342632 -VERTEX_SE2 641 11.552638 -35.529379 -2.352802 -VERTEX_SE2 642 11.112191 -35.949492 -2.400353 -VERTEX_SE2 643 10.731895 -36.277399 -2.465381 -VERTEX_SE2 644 10.729340 -36.284109 -1.701776 -VERTEX_SE2 645 10.869715 -36.451460 -0.744873 -VERTEX_SE2 646 11.382066 -36.817597 -0.447477 -VERTEX_SE2 647 11.978978 -37.021611 -0.156322 -VERTEX_SE2 648 12.612056 -37.054234 0.012089 -VERTEX_SE2 649 13.205551 -37.119561 -0.322437 -VERTEX_SE2 650 13.749716 -37.452144 -0.576811 -VERTEX_SE2 651 13.876986 -37.522144 0.229018 -VERTEX_SE2 652 13.879256 -37.519914 1.262617 -VERTEX_SE2 653 13.872372 -37.502026 2.301465 -VERTEX_SE2 654 13.581181 -37.403460 2.818912 -VERTEX_SE2 655 13.048482 -37.219840 2.815600 -VERTEX_SE2 656 12.474722 -37.010334 2.804516 -VERTEX_SE2 657 11.844104 -36.899464 3.083365 -VERTEX_SE2 658 11.204549 -36.869297 3.076381 -VERTEX_SE2 659 10.709556 -36.810477 3.005332 -VERTEX_SE2 660 10.703219 -36.809512 -2.677502 -VERTEX_SE2 661 10.609221 -37.000250 -2.023854 -VERTEX_SE2 662 10.337163 -37.568215 -1.954223 -VERTEX_SE2 663 10.139552 -38.159090 -1.853215 -VERTEX_SE2 664 10.135226 -38.165415 -1.314901 -VERTEX_SE2 665 10.170577 -38.183639 -0.436050 -VERTEX_SE2 666 10.743964 -38.430041 -0.401598 -VERTEX_SE2 667 11.280508 -38.651643 -0.399484 -VERTEX_SE2 668 11.840921 -38.888748 -0.376305 -VERTEX_SE2 669 12.435464 -39.121854 -0.404047 -VERTEX_SE2 670 13.006910 -39.403898 -0.466305 -VERTEX_SE2 671 13.282608 -39.541377 -0.414044 -VERTEX_SE2 672 12.769426 -39.275957 -0.506105 -VERTEX_SE2 673 12.545541 -39.138628 -0.639846 -VERTEX_SE2 674 12.542473 -39.133012 -1.294945 -VERTEX_SE2 675 12.544204 -39.117309 -1.910166 -VERTEX_SE2 676 12.549939 -39.112303 -2.540226 -VERTEX_SE2 677 12.562810 -39.108340 3.120460 -VERTEX_SE2 678 12.373080 -39.013683 2.669222 -VERTEX_SE2 679 11.859571 -38.764102 2.729006 -VERTEX_SE2 680 11.438738 -38.641448 3.069344 -VERTEX_SE2 681 10.825052 -38.579071 3.043558 -VERTEX_SE2 682 10.191857 -38.531816 3.093190 -VERTEX_SE2 683 9.891918 -38.522270 -3.028351 -VERTEX_SE2 684 9.884198 -38.525775 -1.959011 -VERTEX_SE2 685 9.893810 -38.971112 -1.519535 -VERTEX_SE2 686 9.862204 -39.454619 -1.666211 -VERTEX_SE2 687 9.788467 -40.084236 -1.702984 -VERTEX_SE2 688 9.681861 -40.709183 -1.716237 -VERTEX_SE2 689 9.605655 -41.306367 -1.689887 -VERTEX_SE2 690 9.568647 -41.883115 -1.616935 -VERTEX_SE2 691 9.547797 -42.313693 -1.645939 -VERTEX_SE2 692 9.547338 -42.304642 -1.113930 -VERTEX_SE2 693 9.542348 -42.304320 -0.077783 -VERTEX_SE2 694 9.537355 -42.304058 0.754255 -VERTEX_SE2 695 9.537558 -42.302067 1.551174 -VERTEX_SE2 696 9.534841 -42.288755 2.572731 -VERTEX_SE2 697 9.523163 -42.279299 2.318206 -VERTEX_SE2 698 9.451431 -41.889589 1.660453 -VERTEX_SE2 699 9.371393 -41.248546 1.772879 -VERTEX_SE2 700 9.226326 -40.627573 1.824729 -VERTEX_SE2 701 9.049173 -40.073867 1.881983 -VERTEX_SE2 702 8.937709 -39.503989 1.764440 -VERTEX_SE2 703 8.820349 -38.895181 1.796436 -VERTEX_SE2 704 8.652821 -38.280287 1.812200 -VERTEX_SE2 705 8.469818 -37.662927 1.876685 -VERTEX_SE2 706 8.352303 -37.160636 1.599049 -VERTEX_SE2 707 8.353815 -37.156710 1.065513 -VERTEX_SE2 708 8.350433 -37.159057 0.410972 -VERTEX_SE2 709 8.285591 -37.179408 0.069240 -VERTEX_SE2 710 8.271325 -37.178203 -0.506017 -VERTEX_SE2 711 8.272256 -37.177853 -1.117758 -VERTEX_SE2 712 8.271421 -37.172816 -1.692402 -VERTEX_SE2 713 8.082147 -37.631033 -1.986694 -VERTEX_SE2 714 7.781665 -38.118818 -2.191858 -VERTEX_SE2 715 7.436278 -38.650634 -2.086627 -VERTEX_SE2 716 7.101560 -39.196310 -2.222833 -VERTEX_SE2 717 6.732648 -39.710336 -2.136309 -VERTEX_SE2 718 6.249991 -40.323558 -2.309481 -VERTEX_SE2 719 5.841996 -40.813346 -2.233064 -VERTEX_SE2 720 5.439595 -41.301667 -2.290296 -VERTEX_SE2 721 5.032639 -41.793490 -2.219961 -VERTEX_SE2 722 5.017459 -41.813716 -2.151150 -VERTEX_SE2 723 5.020505 -41.823419 -1.052793 -VERTEX_SE2 724 5.031411 -41.829247 0.024382 -VERTEX_SE2 725 5.041952 -41.823519 0.663795 -VERTEX_SE2 726 5.186097 -41.536150 1.121855 -VERTEX_SE2 727 5.441157 -40.953385 1.154429 -VERTEX_SE2 728 5.708786 -40.374749 1.157456 -VERTEX_SE2 729 5.942746 -39.779976 1.216830 -VERTEX_SE2 730 6.141286 -39.181998 1.255908 -VERTEX_SE2 731 6.337960 -38.578088 1.269244 -VERTEX_SE2 732 6.370731 -38.458677 1.718146 -VERTEX_SE2 733 6.369310 -38.458803 2.719136 -VERTEX_SE2 734 5.849568 -38.267284 2.798462 -VERTEX_SE2 735 5.287090 -38.058027 2.767482 -VERTEX_SE2 736 5.282360 -38.056088 -2.913613 -VERTEX_SE2 737 5.275781 -38.066121 -2.109607 -VERTEX_SE2 738 4.978024 -38.585828 -2.089531 -VERTEX_SE2 739 4.620518 -39.102322 -2.146106 -VERTEX_SE2 740 4.357016 -39.553955 -2.081799 -VERTEX_SE2 741 4.357431 -39.553064 -2.448926 -VERTEX_SE2 742 4.347527 -39.558696 -3.099199 -VERTEX_SE2 743 4.342558 -39.557580 2.569578 -VERTEX_SE2 744 4.336078 -39.550170 2.032393 -VERTEX_SE2 745 4.335980 -39.547933 1.441244 -VERTEX_SE2 746 4.573919 -39.080308 0.968419 -VERTEX_SE2 747 4.940154 -38.557294 0.934212 -VERTEX_SE2 748 5.302092 -38.106400 0.867038 -VERTEX_SE2 749 5.345738 -38.052022 1.298344 -VERTEX_SE2 750 5.342230 -38.047361 2.229268 -VERTEX_SE2 751 5.083575 -37.967511 2.872246 -VERTEX_SE2 752 4.493353 -37.766114 2.770046 -VERTEX_SE2 753 3.897446 -37.540993 2.834236 -VERTEX_SE2 754 3.312644 -37.288841 2.673214 -VERTEX_SE2 755 2.737782 -37.020556 2.749498 -VERTEX_SE2 756 2.174638 -36.731322 2.558054 -VERTEX_SE2 757 1.632084 -36.401074 2.656949 -VERTEX_SE2 758 1.085717 -36.165115 2.783429 -VERTEX_SE2 759 0.594312 -35.911010 2.644238 -VERTEX_SE2 760 0.049628 -35.662561 2.758388 -VERTEX_SE2 761 0.027544 -35.652794 2.941901 -VERTEX_SE2 762 0.026506 -35.653762 -2.331733 -VERTEX_SE2 763 -0.256374 -36.186295 -2.039623 -VERTEX_SE2 764 -0.462375 -36.581571 -2.067616 -VERTEX_SE2 765 -0.464849 -36.589741 -1.429340 -VERTEX_SE2 766 -0.458452 -36.594227 -0.430727 -VERTEX_SE2 767 -0.455458 -36.594045 0.498539 -VERTEX_SE2 768 -0.452643 -36.586959 1.219631 -VERTEX_SE2 769 -0.342345 -35.973305 1.375930 -VERTEX_SE2 770 -0.198947 -35.353053 1.308266 -VERTEX_SE2 771 -0.182607 -35.284960 1.867596 -VERTEX_SE2 772 -0.189467 -35.280006 2.733492 -VERTEX_SE2 773 -0.733580 -35.074067 2.818690 -VERTEX_SE2 774 -1.260348 -34.911848 2.840206 -VERTEX_SE2 775 -1.264437 -34.911446 -2.599985 -VERTEX_SE2 776 -1.363996 -35.119485 -1.984041 -VERTEX_SE2 777 -1.608279 -35.704951 -1.925618 -VERTEX_SE2 778 -1.822302 -36.299953 -1.947124 -VERTEX_SE2 779 -2.047440 -36.894571 -1.929730 -VERTEX_SE2 780 -2.139238 -37.102862 -2.060860 -VERTEX_SE2 781 -2.145402 -37.110533 -2.636030 -VERTEX_SE2 782 -2.437259 -37.141405 -3.067105 -VERTEX_SE2 783 -3.047824 -37.175458 -3.068514 -VERTEX_SE2 784 -3.287219 -37.194026 -3.090710 -VERTEX_SE2 785 -3.295317 -37.191509 2.638474 -VERTEX_SE2 786 -3.298918 -37.188857 2.048008 -VERTEX_SE2 787 -3.298039 -37.190654 1.555448 -VERTEX_SE2 788 -3.294912 -37.183493 0.924060 -VERTEX_SE2 789 -3.288075 -37.179210 0.370053 -VERTEX_SE2 790 -2.810788 -37.026036 0.301996 -VERTEX_SE2 791 -2.219090 -36.811172 0.399811 -VERTEX_SE2 792 -1.939736 -36.661187 1.102401 -VERTEX_SE2 793 -1.678873 -36.103497 1.143891 -VERTEX_SE2 794 -1.429675 -35.516238 1.211715 -VERTEX_SE2 795 -1.418449 -35.555793 1.634956 -VERTEX_SE2 796 -1.418085 -35.571576 2.285912 -VERTEX_SE2 797 -1.667269 -35.397655 2.541335 -VERTEX_SE2 798 -2.187789 -35.048694 2.588216 -VERTEX_SE2 799 -2.741194 -34.735022 2.650579 -VERTEX_SE2 800 -3.307545 -34.448654 2.720068 -VERTEX_SE2 801 -3.902341 -34.216184 2.802965 -VERTEX_SE2 802 -4.505679 -34.024853 2.857856 -VERTEX_SE2 803 -5.085804 -33.763383 2.689794 -VERTEX_SE2 804 -5.662771 -33.497682 2.743005 -VERTEX_SE2 805 -6.261534 -33.279468 2.816554 -VERTEX_SE2 806 -6.840015 -33.097367 2.855463 -VERTEX_SE2 807 -7.023476 -33.048729 -3.135502 -VERTEX_SE2 808 -7.026802 -33.056076 -2.177404 -VERTEX_SE2 809 -7.281242 -33.594521 -2.029487 -VERTEX_SE2 810 -7.631595 -34.121859 -2.166451 -VERTEX_SE2 811 -7.962424 -34.637653 -2.167266 -VERTEX_SE2 812 -7.965744 -34.642706 -1.427803 -VERTEX_SE2 813 -7.950068 -34.658744 -0.442321 -VERTEX_SE2 814 -7.946972 -34.656894 0.560269 -VERTEX_SE2 815 -7.933401 -34.640091 1.489098 -VERTEX_SE2 816 -7.934735 -34.631584 2.177465 -VERTEX_SE2 817 -7.937452 -34.619639 1.515677 -VERTEX_SE2 818 -7.834770 -34.423652 1.032291 -VERTEX_SE2 819 -7.526530 -33.907724 1.048948 -VERTEX_SE2 820 -7.214976 -33.390015 1.010358 -VERTEX_SE2 821 -6.920703 -32.916256 1.028688 -VERTEX_SE2 822 -6.919798 -32.914444 1.802164 -VERTEX_SE2 823 -6.939217 -32.906160 2.735576 -VERTEX_SE2 824 -7.523314 -32.665202 2.656921 -VERTEX_SE2 825 -8.081019 -32.349406 2.627743 -VERTEX_SE2 826 -8.677362 -32.112604 2.791147 -VERTEX_SE2 827 -9.263427 -31.871967 2.742741 -VERTEX_SE2 828 -9.860125 -31.638542 2.778381 -VERTEX_SE2 829 -10.419194 -31.408540 2.739767 -VERTEX_SE2 830 -10.979677 -31.164322 2.732511 -VERTEX_SE2 831 -11.504644 -30.911305 2.686863 -VERTEX_SE2 832 -12.017274 -30.666706 2.684351 -VERTEX_SE2 833 -12.247951 -30.553587 2.823368 -VERTEX_SE2 834 -12.252957 -30.553546 -2.400674 -VERTEX_SE2 835 -12.257933 -30.565509 -1.619664 -VERTEX_SE2 836 -12.250730 -30.581427 -0.672599 -VERTEX_SE2 837 -12.229702 -30.583353 0.368164 -VERTEX_SE2 838 -12.218778 -30.573267 1.234031 -VERTEX_SE2 839 -12.217846 -30.572182 1.017315 -VERTEX_SE2 840 -12.205638 -30.563033 0.457221 -VERTEX_SE2 841 -12.186893 -30.559209 -0.157128 -VERTEX_SE2 842 -11.953603 -30.647983 -0.386378 -VERTEX_SE2 843 -11.425785 -30.867365 -0.387868 -VERTEX_SE2 844 -10.836985 -31.098902 -0.394843 -VERTEX_SE2 845 -10.253132 -31.347696 -0.408511 -VERTEX_SE2 846 -9.662939 -31.589256 -0.405754 -VERTEX_SE2 847 -9.086083 -31.851482 -0.431429 -VERTEX_SE2 848 -8.940268 -31.914214 0.052760 -VERTEX_SE2 849 -8.937884 -31.910733 0.981233 -VERTEX_SE2 850 -8.846299 -31.550192 1.337597 -VERTEX_SE2 851 -8.670841 -30.931185 1.246884 -VERTEX_SE2 852 -8.462808 -30.325041 1.262739 -VERTEX_SE2 853 -8.280607 -29.742061 1.236186 -VERTEX_SE2 854 -8.076287 -29.173781 1.239399 -VERTEX_SE2 855 -7.887388 -28.592768 1.238706 -VERTEX_SE2 856 -7.661883 -27.996043 1.201622 -VERTEX_SE2 857 -7.435282 -27.400366 1.195491 -VERTEX_SE2 858 -7.181293 -26.816604 1.144746 -VERTEX_SE2 859 -6.975384 -26.352422 1.141340 -VERTEX_SE2 860 -6.975931 -26.349425 2.005134 -VERTEX_SE2 861 -7.070368 -26.315710 2.933845 -VERTEX_SE2 862 -7.703743 -26.156922 2.877954 -VERTEX_SE2 863 -8.318477 -25.984947 2.848940 -VERTEX_SE2 864 -8.894038 -25.792766 2.850044 -VERTEX_SE2 865 -9.480815 -25.646186 2.911227 -VERTEX_SE2 866 -10.042232 -25.502772 2.913209 -VERTEX_SE2 867 -10.195104 -25.469004 3.098784 -VERTEX_SE2 868 -10.213426 -25.478919 -2.146684 -VERTEX_SE2 869 -10.215119 -25.492408 -1.155028 -VERTEX_SE2 870 -10.214332 -25.494499 -0.141931 -VERTEX_SE2 871 -10.213017 -25.492991 0.844964 -VERTEX_SE2 872 -10.207635 -25.487052 1.539524 -VERTEX_SE2 873 -10.203844 -25.478644 0.974807 -VERTEX_SE2 874 -10.191816 -25.467641 0.422903 -VERTEX_SE2 875 -10.178876 -25.463448 -0.155631 -VERTEX_SE2 876 -9.623904 -25.632105 -0.308985 -VERTEX_SE2 877 -9.083899 -25.830525 -0.389894 -VERTEX_SE2 878 -8.876969 -25.899540 -0.000578 -VERTEX_SE2 879 -8.229916 -25.842173 0.054103 -VERTEX_SE2 880 -7.774580 -25.835590 -0.054479 -VERTEX_SE2 881 -7.817933 -25.833359 -0.045761 -VERTEX_SE2 882 -7.174094 -25.927843 -0.286988 -VERTEX_SE2 883 -6.578127 -26.179696 -0.472812 -VERTEX_SE2 884 -6.240032 -26.360890 -0.535840 -VERTEX_SE2 885 -6.234259 -26.360820 0.054937 -VERTEX_SE2 886 -6.226914 -26.353411 1.089009 -VERTEX_SE2 887 -6.223165 -26.344082 2.116331 -VERTEX_SE2 888 -6.228613 -26.341527 3.115899 -VERTEX_SE2 889 -6.233959 -26.343474 -2.255359 -VERTEX_SE2 890 -6.384262 -26.679298 -1.975677 -VERTEX_SE2 891 -6.638596 -27.241278 -2.042104 -VERTEX_SE2 892 -6.943864 -27.800951 -2.074085 -VERTEX_SE2 893 -7.222566 -28.381189 -1.832614 -VERTEX_SE2 894 -7.306963 -29.019629 -1.606544 -VERTEX_SE2 895 -7.223579 -29.638727 -1.302591 -VERTEX_SE2 896 -7.217764 -29.658031 -0.821107 -VERTEX_SE2 897 -6.741710 -29.937142 -0.546756 -VERTEX_SE2 898 -6.211746 -30.256253 -0.528856 -VERTEX_SE2 899 -5.784445 -30.515658 -0.593948 -VERTEX_SE2 900 -5.213641 -30.892109 -0.593973 -VERTEX_SE2 901 -4.743942 -31.232862 -0.655646 -VERTEX_SE2 902 -4.223039 -31.613559 -0.627847 -VERTEX_SE2 903 -3.820846 -31.901295 -0.669947 -VERTEX_SE2 904 -3.815849 -31.904352 0.045079 -VERTEX_SE2 905 -3.263955 -31.843907 0.103405 -VERTEX_SE2 906 -2.639473 -31.754495 0.172374 -VERTEX_SE2 907 -2.019027 -31.639234 0.167356 -VERTEX_SE2 908 -1.390615 -31.531155 0.192144 -VERTEX_SE2 909 -0.774159 -31.409648 0.174319 -VERTEX_SE2 910 -0.621113 -31.427046 -0.195369 -VERTEX_SE2 911 -0.014492 -31.535247 -0.134304 -VERTEX_SE2 912 0.586470 -31.609953 -0.123402 -VERTEX_SE2 913 1.163336 -31.678045 -0.116774 -VERTEX_SE2 914 1.788505 -31.757735 -0.141346 -VERTEX_SE2 915 2.338537 -31.842759 -0.178606 -VERTEX_SE2 916 2.533087 -31.771891 0.368065 -VERTEX_SE2 917 3.132539 -31.589985 0.113800 -VERTEX_SE2 918 3.652121 -31.566106 0.038805 -VERTEX_SE2 919 4.280972 -31.547492 -0.003530 -VERTEX_SE2 920 4.910829 -31.560372 -0.019732 -VERTEX_SE2 921 5.544993 -31.581438 -0.071106 -VERTEX_SE2 922 6.178198 -31.632867 -0.095979 -VERTEX_SE2 923 6.782469 -31.705277 -0.156454 -VERTEX_SE2 924 7.306767 -31.788672 -0.137071 -VERTEX_SE2 925 7.316981 -31.785338 0.373816 -VERTEX_SE2 926 7.870711 -31.558218 0.392795 -VERTEX_SE2 927 8.451492 -31.319547 0.372320 -VERTEX_SE2 928 9.048413 -31.086577 0.366185 -VERTEX_SE2 929 9.642832 -30.858817 0.368104 -VERTEX_SE2 930 10.245448 -30.641674 0.289261 -VERTEX_SE2 931 10.860347 -30.480136 0.213162 -VERTEX_SE2 932 11.487766 -30.354631 0.158095 -VERTEX_SE2 933 12.113942 -30.270301 0.098329 -VERTEX_SE2 934 12.615349 -30.217794 0.093110 -VERTEX_SE2 935 12.620802 -30.215724 0.789990 -VERTEX_SE2 936 12.621200 -30.213495 1.735352 -VERTEX_SE2 937 12.506666 -29.673239 1.798228 -VERTEX_SE2 938 12.424893 -29.074588 1.624736 -VERTEX_SE2 939 12.382460 -28.442898 1.652316 -VERTEX_SE2 940 12.358048 -27.806499 1.569594 -VERTEX_SE2 941 12.373922 -27.170573 1.518896 -VERTEX_SE2 942 12.403040 -26.619551 1.526103 -VERTEX_SE2 943 12.433212 -25.976160 1.617626 -VERTEX_SE2 944 12.409024 -25.337583 1.563948 -VERTEX_SE2 945 12.425512 -24.701834 1.511054 -VERTEX_SE2 946 12.438281 -24.522578 1.577626 -VERTEX_SE2 947 12.297194 -24.116617 1.909253 -VERTEX_SE2 948 12.106012 -23.569193 1.887290 -VERTEX_SE2 949 11.964410 -22.979201 1.728071 -VERTEX_SE2 950 11.889816 -22.346608 1.484552 -VERTEX_SE2 951 11.958985 -21.712798 1.409506 -VERTEX_SE2 952 12.033066 -21.078819 1.656468 -VERTEX_SE2 953 11.960841 -20.446967 1.733995 -VERTEX_SE2 954 11.870328 -19.821157 1.720988 -VERTEX_SE2 955 11.840813 -19.182342 1.553709 -VERTEX_SE2 956 11.856933 -18.549356 1.547775 -VERTEX_SE2 957 11.900583 -17.914412 1.456986 -VERTEX_SE2 958 11.980717 -17.309521 1.428422 -VERTEX_SE2 959 12.082916 -16.713544 1.360362 -VERTEX_SE2 960 12.156646 -16.109750 1.448732 -VERTEX_SE2 961 12.237458 -15.513097 1.428643 -VERTEX_SE2 962 12.263723 -14.879685 1.501648 -VERTEX_SE2 963 12.237575 -14.246674 1.697303 -VERTEX_SE2 964 12.165060 -13.610953 1.639856 -VERTEX_SE2 965 12.127557 -12.978752 1.638378 -VERTEX_SE2 966 12.104648 -12.566160 1.581231 -VERTEX_SE2 967 12.101573 -12.558682 2.440323 -VERTEX_SE2 968 12.096363 -12.554972 -2.940213 -VERTEX_SE2 969 12.095404 -12.555254 -2.878924 -VERTEX_SE2 970 12.095404 -12.555254 -2.879037 -VERTEX_SE2 971 11.746171 -12.650445 -2.877325 -VERTEX_SE2 972 11.152947 -12.816606 -2.870194 -VERTEX_SE2 973 10.545291 -12.861291 3.130276 -VERTEX_SE2 974 9.909280 -12.851322 -3.119743 -VERTEX_SE2 975 9.273543 -12.871196 -3.113968 -VERTEX_SE2 976 8.636290 -12.899229 -3.099985 -VERTEX_SE2 977 7.998434 -12.914064 -3.126289 -VERTEX_SE2 978 7.362084 -12.942484 -3.081464 -VERTEX_SE2 979 6.727323 -12.975809 -3.095884 -VERTEX_SE2 980 6.088538 -13.025797 -3.052420 -VERTEX_SE2 981 5.456362 -13.081213 -3.049818 -VERTEX_SE2 982 4.878233 -13.153816 -3.010682 -VERTEX_SE2 983 4.276746 -13.227843 -3.016388 -VERTEX_SE2 984 3.677713 -13.322859 -2.961936 -VERTEX_SE2 985 3.077590 -13.433257 -2.944700 -VERTEX_SE2 986 2.454219 -13.573733 -2.911877 -VERTEX_SE2 987 1.831643 -13.709396 -2.952510 -VERTEX_SE2 988 1.208691 -13.826413 -2.942854 -VERTEX_SE2 989 0.584787 -13.958913 -2.938610 -VERTEX_SE2 990 -0.036556 -14.080445 -2.953180 -VERTEX_SE2 991 -0.661927 -14.209275 -2.932525 -VERTEX_SE2 992 -1.260572 -14.319726 -2.969755 -VERTEX_SE2 993 -1.888936 -14.441757 -2.941917 -VERTEX_SE2 994 -2.487885 -14.558335 -2.956980 -VERTEX_SE2 995 -3.058043 -14.679439 -2.909164 -VERTEX_SE2 996 -3.642056 -14.831099 -2.881732 -VERTEX_SE2 997 -4.264284 -14.974196 -2.946069 -VERTEX_SE2 998 -4.649607 -15.053751 -2.924278 -VERTEX_SE2 999 -4.656689 -15.065859 -2.206631 -VERTEX_SE2 1000 -4.965388 -15.623496 -2.058280 -VERTEX_SE2 1001 -5.318062 -16.158055 -2.379913 -VERTEX_SE2 1002 -5.750626 -16.618291 -2.287924 -VERTEX_SE2 1003 -6.211655 -17.061941 -2.468589 -VERTEX_SE2 1004 -6.694526 -17.473495 -2.405819 -VERTEX_SE2 1005 -7.127979 -17.892536 -2.338545 -VERTEX_SE2 1006 -7.533434 -18.348428 -2.255884 -VERTEX_SE2 1007 -7.879092 -18.809574 -2.158490 -VERTEX_SE2 1008 -8.039907 -19.059004 -1.992248 -VERTEX_SE2 1009 -8.036682 -19.246221 -1.535293 -VERTEX_SE2 1010 -8.014039 -19.881169 -1.488904 -VERTEX_SE2 1011 -7.963340 -20.508886 -1.536571 -VERTEX_SE2 1012 -7.940438 -21.138959 -1.498741 -VERTEX_SE2 1013 -7.851368 -21.773013 -1.387987 -VERTEX_SE2 1014 -7.817932 -22.401411 -1.567544 -VERTEX_SE2 1015 -7.777031 -23.038795 -1.486212 -VERTEX_SE2 1016 -7.720006 -23.818187 -1.481750 -VERTEX_SE2 1017 -7.654678 -24.418258 -1.539186 -VERTEX_SE2 1018 -7.642739 -24.996103 -1.532186 -VERTEX_SE2 1019 -7.587869 -25.606880 -1.473009 -VERTEX_SE2 1020 -7.542280 -26.239004 -1.487341 -VERTEX_SE2 1021 -7.489141 -26.876264 -1.528391 -VERTEX_SE2 1022 -7.485868 -26.947021 -1.536042 -VERTEX_SE2 1023 -7.484661 -26.958141 -1.449942 -VERTEX_SE2 1024 -7.409816 -27.598995 -1.424093 -VERTEX_SE2 1025 -7.295845 -28.237813 -1.407035 -VERTEX_SE2 1026 -7.266936 -28.415848 -1.400374 -VERTEX_SE2 1027 -7.264213 -28.420001 -0.485709 -VERTEX_SE2 1028 -7.082225 -28.411802 0.076550 -VERTEX_SE2 1029 -6.501990 -28.370465 0.054524 -VERTEX_SE2 1030 -5.899285 -28.359129 -0.023135 -VERTEX_SE2 1031 -5.264812 -28.390632 -0.074570 -VERTEX_SE2 1032 -4.627186 -28.437737 -0.067955 -VERTEX_SE2 1033 -3.988448 -28.495960 -0.110249 -VERTEX_SE2 1034 -3.830826 -28.515420 -0.320119 -VERTEX_SE2 1035 -3.824146 -28.521449 -0.932344 -VERTEX_SE2 1036 -3.823513 -28.519287 -1.496421 -VERTEX_SE2 1037 -3.907010 -28.904450 -1.730668 -VERTEX_SE2 1038 -3.935283 -29.554657 -1.636155 -VERTEX_SE2 1039 -4.005708 -30.240003 -1.664719 -VERTEX_SE2 1040 -4.005908 -30.238599 -1.026894 -VERTEX_SE2 1041 -4.005975 -30.237093 0.002348 -VERTEX_SE2 1042 -3.997565 -30.235981 1.002167 -VERTEX_SE2 1043 -3.992361 -30.227413 1.983494 -VERTEX_SE2 1044 -3.977187 -30.235628 2.989203 -VERTEX_SE2 1045 -3.975026 -30.236085 2.875365 -VERTEX_SE2 1046 -3.962563 -30.241673 2.490123 -VERTEX_SE2 1047 -3.950447 -30.258328 1.934722 -VERTEX_SE2 1048 -3.961452 -29.893794 1.621975 -VERTEX_SE2 1049 -4.005576 -29.246490 1.639262 -VERTEX_SE2 1050 -4.077126 -28.603234 1.715064 -VERTEX_SE2 1051 -4.144972 -27.965909 1.641633 -VERTEX_SE2 1052 -4.202505 -27.357765 1.700204 -VERTEX_SE2 1053 -4.242648 -26.957178 1.653111 -VERTEX_SE2 1054 -4.243150 -26.953596 2.434770 -VERTEX_SE2 1055 -4.236475 -26.953142 -2.756219 -VERTEX_SE2 1056 -4.223234 -26.936933 -1.722386 -VERTEX_SE2 1057 -4.227338 -26.917941 -0.719127 -VERTEX_SE2 1058 -4.226406 -26.918299 0.214528 -VERTEX_SE2 1059 -3.650549 -26.814433 0.137155 -VERTEX_SE2 1060 -3.017058 -26.728657 0.145123 -VERTEX_SE2 1061 -2.566458 -26.676490 0.026280 -VERTEX_SE2 1062 -2.547934 -26.680711 -0.534242 -VERTEX_SE2 1063 -2.549662 -26.679283 -1.128091 -VERTEX_SE2 1064 -2.494849 -26.986675 -1.390919 -VERTEX_SE2 1065 -2.341227 -27.585706 -1.267035 -VERTEX_SE2 1066 -2.181042 -28.156133 -1.321458 -VERTEX_SE2 1067 -2.176008 -28.167308 -0.885641 -VERTEX_SE2 1068 -2.171515 -28.170280 -0.208552 -VERTEX_SE2 1069 -2.166440 -28.170156 -0.036102 -VERTEX_SE2 1070 -2.158515 -28.171216 -0.571481 -VERTEX_SE2 1071 -1.728296 -28.528563 -0.696733 -VERTEX_SE2 1072 -1.327331 -28.874102 -0.763594 -VERTEX_SE2 1073 -1.328212 -28.872089 -1.271112 -VERTEX_SE2 1074 -1.186974 -29.415680 -1.303788 -VERTEX_SE2 1075 -1.030631 -30.004733 -1.285588 -VERTEX_SE2 1076 -1.010783 -30.067165 -0.872464 -VERTEX_SE2 1077 -0.990761 -30.068841 -0.051064 -VERTEX_SE2 1078 -0.349127 -30.042537 -0.001133 -VERTEX_SE2 1079 0.251517 -30.025133 0.066104 -VERTEX_SE2 1080 0.250521 -30.025208 -0.411064 -VERTEX_SE2 1081 0.710773 -30.299114 -0.528492 -VERTEX_SE2 1082 0.906064 -30.410866 -0.239852 -VERTEX_SE2 1083 0.893124 -30.419745 0.817776 -VERTEX_SE2 1084 0.892987 -30.410710 1.808848 -VERTEX_SE2 1085 0.877326 -30.393872 2.785923 -VERTEX_SE2 1086 0.299041 -30.311718 3.014416 -VERTEX_SE2 1087 -0.304600 -30.219651 3.001192 -VERTEX_SE2 1088 -0.901080 -30.145015 2.983479 -VERTEX_SE2 1089 -0.971780 -30.133164 2.884958 -VERTEX_SE2 1090 -0.973114 -30.132686 2.263087 -VERTEX_SE2 1091 -1.258802 -29.655877 2.082828 -VERTEX_SE2 1092 -1.565146 -29.096531 2.065302 -VERTEX_SE2 1093 -1.831232 -28.571344 1.997715 -VERTEX_SE2 1094 -1.829673 -28.566075 1.590728 -VERTEX_SE2 1095 -1.822889 -28.540013 0.997280 -VERTEX_SE2 1096 -1.811806 -28.530957 0.422426 -VERTEX_SE2 1097 -1.452357 -28.453682 0.204872 -VERTEX_SE2 1098 -0.806231 -28.342284 0.146524 -VERTEX_SE2 1099 -0.207476 -28.279115 0.048016 -VERTEX_SE2 1100 -0.187763 -28.277509 0.407350 -VERTEX_SE2 1101 0.022408 -28.110407 0.670039 -VERTEX_SE2 1102 0.031962 -28.106738 0.272412 -VERTEX_SE2 1103 0.639388 -27.958876 0.236513 -VERTEX_SE2 1104 1.275605 -27.810841 0.206756 -VERTEX_SE2 1105 1.907140 -27.685723 0.186870 -VERTEX_SE2 1106 2.395193 -27.596899 0.159641 -VERTEX_SE2 1107 2.402168 -27.592873 0.412775 -VERTEX_SE2 1108 2.958139 -27.302229 0.418732 -VERTEX_SE2 1109 3.567153 -27.081855 0.312557 -VERTEX_SE2 1110 4.153225 -26.897988 0.261047 -VERTEX_SE2 1111 4.708902 -26.834648 0.157605 -VERTEX_SE2 1112 5.252614 -26.628115 0.500855 -VERTEX_SE2 1113 5.822286 -26.335525 0.403408 -VERTEX_SE2 1114 6.390291 -26.092686 0.418701 -VERTEX_SE2 1115 6.922867 -25.852780 0.400788 -VERTEX_SE2 1116 7.511667 -25.579208 0.435293 -VERTEX_SE2 1117 7.600383 -25.536976 0.305438 -VERTEX_SE2 1118 7.602610 -25.537159 -0.306056 -VERTEX_SE2 1119 7.600066 -25.535572 -0.741091 -VERTEX_SE2 1120 8.016891 -25.978082 -0.806559 -VERTEX_SE2 1121 8.158671 -26.132496 -0.927181 -VERTEX_SE2 1122 8.158918 -26.136107 -1.481463 -VERTEX_SE2 1123 8.202585 -26.722199 -1.466214 -VERTEX_SE2 1124 8.300951 -27.294198 -1.369439 -VERTEX_SE2 1125 8.427601 -27.927776 -1.357617 -VERTEX_SE2 1126 8.448389 -28.015008 -1.020843 -VERTEX_SE2 1127 8.448797 -28.014120 0.029251 -VERTEX_SE2 1128 8.446703 -28.014495 1.009931 -VERTEX_SE2 1129 8.448367 -28.002253 2.018659 -VERTEX_SE2 1130 8.179683 -27.484075 2.030704 -VERTEX_SE2 1131 8.020715 -26.725314 1.595581 -VERTEX_SE2 1132 8.007311 -26.085207 1.574275 -VERTEX_SE2 1133 8.027146 -25.500857 1.533912 -VERTEX_SE2 1134 8.037276 -25.234473 1.435052 -VERTEX_SE2 1135 8.041135 -25.225813 0.875236 -VERTEX_SE2 1136 8.045119 -25.226197 0.309468 -VERTEX_SE2 1137 8.350426 -25.173106 0.123314 -VERTEX_SE2 1138 9.001574 -25.103517 0.105516 -VERTEX_SE2 1139 9.526482 -25.047001 0.028463 -VERTEX_SE2 1140 9.524465 -25.046883 -0.458084 -VERTEX_SE2 1141 9.526460 -25.047900 -1.013894 -VERTEX_SE2 1142 9.607360 -25.436185 -1.384688 -VERTEX_SE2 1143 9.757086 -26.048918 -1.299305 -VERTEX_SE2 1144 9.911339 -26.642229 -1.333595 -VERTEX_SE2 1145 10.051242 -27.237116 -1.362737 -VERTEX_SE2 1146 10.176396 -27.833614 -1.346612 -VERTEX_SE2 1147 10.348017 -28.420420 -1.277963 -VERTEX_SE2 1148 10.522608 -29.006300 -1.265737 -VERTEX_SE2 1149 10.546607 -29.077059 -0.762568 -VERTEX_SE2 1150 10.540261 -29.074848 0.225763 -VERTEX_SE2 1151 10.553029 -29.065002 1.213625 -VERTEX_SE2 1152 10.547143 -29.052737 2.249842 -VERTEX_SE2 1153 10.539006 -29.045893 -3.036684 -VERTEX_SE2 1154 10.279724 -29.230068 -2.499597 -VERTEX_SE2 1155 9.768765 -29.605741 -2.552981 -VERTEX_SE2 1156 9.258910 -29.939074 -2.546643 -VERTEX_SE2 1157 8.791360 -30.283703 -2.440027 -VERTEX_SE2 1158 8.293580 -30.637927 -2.573320 -VERTEX_SE2 1159 7.766648 -30.929430 -2.672819 -VERTEX_SE2 1160 7.188507 -31.197997 -2.815407 -VERTEX_SE2 1161 6.565573 -31.348475 -2.910356 -VERTEX_SE2 1162 5.944969 -31.503360 -2.857013 -VERTEX_SE2 1163 5.325232 -31.686006 -2.866763 -VERTEX_SE2 1164 4.712273 -31.878415 -2.786199 -VERTEX_SE2 1165 4.215997 -32.064635 -2.806894 -VERTEX_SE2 1166 4.211816 -32.067381 -2.313330 -VERTEX_SE2 1167 4.212397 -32.068184 -1.368491 -VERTEX_SE2 1168 4.215987 -32.071852 -0.457146 -VERTEX_SE2 1169 4.277451 -32.051395 0.371897 -VERTEX_SE2 1170 4.829613 -31.826964 0.380849 -VERTEX_SE2 1171 5.421192 -31.572841 0.415111 -VERTEX_SE2 1172 5.981253 -31.335402 0.355461 -VERTEX_SE2 1173 6.575628 -31.109741 0.367274 -VERTEX_SE2 1174 7.180922 -30.893036 0.301697 -VERTEX_SE2 1175 7.792370 -30.719051 0.271366 -VERTEX_SE2 1176 8.409541 -30.550025 0.230936 -VERTEX_SE2 1177 9.024476 -30.404549 0.236005 -VERTEX_SE2 1178 9.647424 -30.266268 0.192062 -VERTEX_SE2 1179 10.265276 -30.135370 0.224605 -VERTEX_SE2 1180 10.529482 -30.074919 0.220636 -VERTEX_SE2 1181 10.535574 -30.072977 1.058820 -VERTEX_SE2 1182 10.524149 -30.016817 1.779823 -VERTEX_SE2 1183 10.386448 -29.400748 1.808327 -VERTEX_SE2 1184 10.207851 -28.783707 1.881370 -VERTEX_SE2 1185 10.025332 -28.173735 1.852352 -VERTEX_SE2 1186 9.825515 -27.568409 1.922073 -VERTEX_SE2 1187 9.605142 -26.948356 1.888299 -VERTEX_SE2 1188 9.398682 -26.350552 1.909670 -VERTEX_SE2 1189 9.199117 -25.746642 1.931343 -VERTEX_SE2 1190 9.094298 -25.467233 1.939338 -VERTEX_SE2 1191 9.094967 -25.468452 2.859515 -VERTEX_SE2 1192 9.008026 -25.506399 -2.626152 -VERTEX_SE2 1193 8.461781 -25.785098 -2.758330 -VERTEX_SE2 1194 7.923840 -26.019541 -2.716510 -VERTEX_SE2 1195 7.347445 -26.288871 -2.664510 -VERTEX_SE2 1196 6.780364 -26.579172 -2.837709 -VERTEX_SE2 1197 6.180419 -26.774947 -2.826952 -VERTEX_SE2 1198 5.583380 -27.006326 -2.569041 -VERTEX_SE2 1199 5.035569 -27.311853 -2.784743 -VERTEX_SE2 1200 4.440692 -27.555930 -2.716631 -VERTEX_SE2 1201 3.868153 -27.824566 -2.661795 -VERTEX_SE2 1202 3.307623 -28.126760 -2.639885 -VERTEX_SE2 1203 2.784459 -28.432197 -2.731103 -VERTEX_SE2 1204 2.199445 -28.603325 -2.879452 -VERTEX_SE2 1205 1.642686 -28.765416 -2.851240 -VERTEX_SE2 1206 1.070524 -28.960362 -2.791568 -VERTEX_SE2 1207 0.458097 -29.116494 -2.879433 -VERTEX_SE2 1208 -0.157073 -29.300653 -2.816562 -VERTEX_SE2 1209 -0.759388 -29.505640 -2.820223 -VERTEX_SE2 1210 -1.349503 -29.728180 -2.801535 -VERTEX_SE2 1211 -1.962101 -29.894344 -2.871965 -VERTEX_SE2 1212 -2.570554 -30.072460 -2.819915 -VERTEX_SE2 1213 -3.165262 -30.298664 -2.744821 -VERTEX_SE2 1214 -3.865282 -30.564861 -2.965631 -VERTEX_SE2 1215 -4.462533 -30.687173 -2.905497 -VERTEX_SE2 1216 -4.996128 -30.904402 -2.687065 -VERTEX_SE2 1217 -5.548071 -31.150837 -2.705863 -VERTEX_SE2 1218 -6.079683 -31.407444 -2.756532 -VERTEX_SE2 1219 -6.680544 -31.658044 -2.725934 -VERTEX_SE2 1220 -7.206328 -31.919274 -2.635196 -VERTEX_SE2 1221 -7.204948 -31.917957 -3.087949 -VERTEX_SE2 1222 -7.218143 -31.913501 2.597929 -VERTEX_SE2 1223 -7.226028 -31.904243 2.038302 -VERTEX_SE2 1224 -7.405412 -31.351278 1.855394 -VERTEX_SE2 1225 -7.584838 -30.751843 1.869158 -VERTEX_SE2 1226 -7.616041 -30.650012 1.852427 -VERTEX_SE2 1227 -7.616041 -30.650012 1.851765 -EDGE_SE2 0 1 0.000000 0.000000 -0.000642 11.111271 -0.249667 0.000000 399.999840 0.000000 2496.793089 -EDGE_SE2 1 2 0.000000 0.000000 -0.000538 11.111224 -0.209222 0.000000 399.999887 0.000000 2497.312169 -EDGE_SE2 2 3 0.011003 -0.000962 -0.002382 5898.288051 69216.359995 0.000000 813797.504789 0.000000 2488.132420 -EDGE_SE2 3 4 0.630039 -0.007981 -0.003882 11.129692 2.115033 0.000000 251.862638 0.000000 2480.702442 -EDGE_SE2 4 5 0.055010 -0.000106 -0.091282 274.195567 -2936.281177 0.000000 32782.895793 0.000000 2099.259006 -EDGE_SE2 5 6 0.004599 -0.003282 -0.797272 97512.798743 -544001.571431 0.000000 3035217.135802 0.000000 773.949086 -EDGE_SE2 6 7 -0.019286 0.007346 -0.615537 14562.788488 -56611.041711 0.000000 220247.580117 0.000000 957.869160 -EDGE_SE2 7 8 -0.022127 0.006629 -0.613534 18833.046432 -56332.014355 0.000000 168606.730383 0.000000 960.248785 -EDGE_SE2 8 9 -0.021138 0.006734 -0.638070 21300.350989 -62226.140556 0.000000 181891.375069 0.000000 931.697855 -EDGE_SE2 9 10 -0.012731 0.002805 -0.614531 88261.230144 -210099.692864 0.000000 500201.721901 0.000000 959.062847 -EDGE_SE2 10 11 -0.004733 0.001621 -0.674279 455441.532335 -1269769.465818 0.000000 3540210.494348 0.000000 891.834664 -EDGE_SE2 11 12 0.000807 -0.000605 -0.649474 3209.969094 -560838.218926 0.000000 98328698.890567 0.000000 918.859395 -EDGE_SE2 12 13 0.017463 -0.005758 -0.659498 33087.416467 -93212.317327 0.000000 262692.689594 0.000000 907.792399 -EDGE_SE2 13 14 0.024327 -0.007794 -0.608239 13237.887356 -43033.186144 0.000000 140019.158071 0.000000 966.582281 -EDGE_SE2 14 15 0.008665 -0.002176 -0.524928 94975.828833 -331589.466697 0.000000 1157826.108740 0.000000 1075.081358 -EDGE_SE2 15 16 0.300013 0.002659 -0.018692 11.945981 -30.290393 0.000000 1110.094393 0.000000 2409.096616 -EDGE_SE2 16 17 0.618894 -0.006590 -0.031228 11.216951 -5.142163 0.000000 260.940781 0.000000 2350.880836 -EDGE_SE2 17 18 0.644399 0.002908 -0.010177 11.160679 -3.373944 0.000000 240.764207 0.000000 2449.881377 -EDGE_SE2 18 19 0.657345 -0.022632 -0.048576 11.155234 -3.115574 0.000000 231.108306 0.000000 2273.736754 -EDGE_SE2 19 20 0.644638 0.002939 0.010643 11.119605 1.396220 0.000000 240.626947 0.000000 2447.622654 -EDGE_SE2 20 21 0.643768 0.040732 0.117695 11.791489 12.469629 0.000000 239.648403 0.000000 2001.213355 -EDGE_SE2 21 22 0.641586 -0.019837 0.022682 11.775592 12.387374 0.000000 242.038634 0.000000 2390.335076 -EDGE_SE2 22 23 0.642142 0.071066 0.114072 11.114499 0.879730 0.000000 239.576730 0.000000 2014.250547 -EDGE_SE2 23 24 0.642775 -0.026027 -0.050939 11.136380 -2.413434 0.000000 241.616002 0.000000 2263.523413 -EDGE_SE2 24 25 0.645593 0.014612 0.008602 11.156105 -3.207460 0.000000 239.760661 0.000000 2457.538661 -EDGE_SE2 25 26 0.612608 -0.020554 -0.040332 11.122880 -1.732513 0.000000 266.150269 0.000000 2309.915505 -EDGE_SE2 26 27 0.617908 0.014448 0.016074 11.124480 -1.830524 0.000000 261.753630 0.000000 2421.527089 -EDGE_SE2 27 28 0.585700 -0.007698 -0.004161 11.133727 2.517886 0.000000 291.434633 0.000000 2479.324138 -EDGE_SE2 28 29 0.378831 0.003536 0.031104 11.435983 14.920983 0.000000 696.414325 0.000000 2351.446301 -EDGE_SE2 29 30 0.007031 -0.000919 -0.531386 303620.480641 -715329.968352 0.000000 1685390.466875 0.000000 1066.033037 -EDGE_SE2 30 31 0.172814 -0.047579 -0.267833 11.113242 2.570601 0.000000 3112.523002 0.000000 1555.306207 -EDGE_SE2 31 32 0.643089 -0.013458 -0.018151 11.112884 0.639397 0.000000 241.693017 0.000000 2411.657469 -EDGE_SE2 32 33 0.641505 0.012210 0.053138 11.380647 7.899680 0.000000 242.638725 0.000000 2254.080602 -EDGE_SE2 33 34 0.642958 0.012818 0.023470 11.113996 0.815809 0.000000 241.800271 0.000000 2386.655713 -EDGE_SE2 34 35 0.642138 0.012026 0.036992 11.188281 4.224347 0.000000 242.355561 0.000000 2324.819270 -EDGE_SE2 35 36 0.646989 -0.005904 -0.005774 11.113668 0.763126 0.000000 238.872355 0.000000 2471.378132 -EDGE_SE2 36 37 0.422413 0.003265 0.010657 11.115820 1.608217 0.000000 560.397185 0.000000 2447.554843 -EDGE_SE2 37 38 0.004147 -0.000362 -0.316561 298816.394178 -1278713.788579 0.000000 5472166.543975 0.000000 1442.308081 -EDGE_SE2 38 39 0.031682 -0.005795 -0.166903 29.991712 1348.903464 0.000000 96382.012864 0.000000 1835.990780 -EDGE_SE2 39 40 0.628745 0.004932 0.020565 11.150244 3.076040 0.000000 252.904983 0.000000 2400.262103 -EDGE_SE2 40 41 0.654706 -0.007135 -0.028394 11.179108 -3.886059 0.000000 233.200483 0.000000 2363.855583 -EDGE_SE2 41 42 0.615233 -0.005892 -0.018963 11.133406 -2.375163 0.000000 264.145862 0.000000 2407.815356 -EDGE_SE2 42 43 0.646018 -0.015551 -0.036078 11.144050 -2.742429 0.000000 239.441473 0.000000 2328.922864 -EDGE_SE2 43 44 0.644889 -0.007273 -0.032646 11.215795 -4.898393 0.000000 240.317651 0.000000 2344.428944 -EDGE_SE2 44 45 0.642617 -0.019475 -0.055423 11.256800 -5.797160 0.000000 241.788650 0.000000 2244.330959 -EDGE_SE2 45 46 0.643577 -0.008674 -0.019276 11.118853 -1.335200 0.000000 241.382966 0.000000 2406.336795 -EDGE_SE2 46 47 0.643124 -0.007411 -0.041538 11.318826 -6.918261 0.000000 241.534792 0.000000 2304.569286 -EDGE_SE2 47 48 0.647528 -0.005000 -0.006399 11.111509 0.300792 0.000000 238.482697 0.000000 2468.309505 -EDGE_SE2 48 49 0.643552 -0.004657 -0.050649 11.544947 -9.986829 0.000000 241.006497 0.000000 2264.773140 -EDGE_SE2 49 50 0.613650 -0.021431 -0.044298 11.133509 -2.385631 0.000000 265.211665 0.000000 2292.403781 -EDGE_SE2 50 51 0.614419 0.001282 -0.030028 11.372766 -8.144597 0.000000 264.630129 0.000000 2356.361658 -EDGE_SE2 51 52 0.612275 -0.025515 -0.077517 11.439261 -9.144885 0.000000 265.960759 0.000000 2153.236570 -EDGE_SE2 52 53 0.589010 0.013532 0.011867 11.145260 -3.075254 0.000000 288.053971 0.000000 2441.704725 -EDGE_SE2 53 54 0.549942 -0.015900 -0.062397 11.469128 -10.685144 0.000000 330.013480 0.000000 2214.962293 -EDGE_SE2 54 55 -0.007990 -0.000400 0.004985 3173.514815 -70220.700546 0.000000 1559251.248529 0.000000 2475.260146 -EDGE_SE2 55 56 0.031075 -0.000065 0.010280 26.926592 1279.597558 0.000000 103540.680562 0.000000 2449.381862 -EDGE_SE2 56 57 0.661651 0.003067 -0.011448 11.167314 -3.494319 0.000000 228.362912 0.000000 2443.728134 -EDGE_SE2 57 58 0.651514 0.005099 0.046426 11.445370 8.655456 0.000000 235.239298 0.000000 2283.089649 -EDGE_SE2 58 59 0.644894 -0.007287 -0.023143 11.143280 -2.715787 0.000000 240.386652 0.000000 2388.181524 -EDGE_SE2 59 60 0.641666 0.006484 0.022061 11.144235 2.770355 0.000000 242.816230 0.000000 2393.240674 -EDGE_SE2 60 61 0.644092 -0.013088 -0.049766 11.310377 -6.764558 0.000000 240.749901 0.000000 2268.584724 -EDGE_SE2 61 62 0.610542 0.010202 0.039027 11.239154 5.735944 0.000000 268.065336 0.000000 2315.721577 -EDGE_SE2 62 63 0.615687 -0.014578 -0.037143 11.156928 -3.401279 0.000000 263.609811 0.000000 2324.142368 -EDGE_SE2 63 64 0.614457 0.023223 0.060765 11.244984 5.822514 0.000000 264.348682 0.000000 2221.783030 -EDGE_SE2 64 65 0.613126 -0.015622 -0.054905 11.331684 -7.492495 0.000000 265.618387 0.000000 2246.535610 -EDGE_SE2 65 66 0.642083 0.005221 -0.012134 11.206140 -4.688688 0.000000 242.448428 0.000000 2440.416656 -EDGE_SE2 66 67 0.644032 -0.000439 -0.003525 11.112971 -0.654045 0.000000 241.091541 0.000000 2482.467756 -EDGE_SE2 67 68 0.480969 0.003132 -0.018150 11.367193 -10.381901 0.000000 432.006963 0.000000 2411.662206 -EDGE_SE2 68 69 0.010004 -0.000372 -0.158022 14522.704416 -119457.061100 0.000000 983362.087562 0.000000 1864.259601 -EDGE_SE2 69 70 0.007781 -0.000530 -0.680912 544035.164858 -773651.719241 0.000000 1100214.270443 0.000000 884.810063 -EDGE_SE2 70 71 -0.005768 0.002595 -0.648935 125743.539339 -546312.647396 0.000000 2373762.361377 0.000000 919.460202 -EDGE_SE2 71 72 0.000000 0.000000 -0.011790 11.165166 -4.584575 0.000000 399.945945 0.000000 2442.076380 -EDGE_SE2 72 73 0.003590 -0.000252 -0.067514 59.238767 19279.280557 0.000000 7723027.108236 0.000000 2193.777612 -EDGE_SE2 73 74 0.003377 -0.001263 -0.627884 547328.125180 -1977782.419372 0.000000 7146917.196299 0.000000 943.393977 -EDGE_SE2 74 75 0.001263 0.000666 -0.356531 27289611.550657 -24363663.505902 0.000000 21751450.848890 0.000000 1358.565441 -EDGE_SE2 75 76 0.014525 0.005731 0.687334 38537.927166 119650.043523 0.000000 371599.899935 0.000000 878.087699 -EDGE_SE2 76 77 0.012722 0.001600 0.229532 6624.040036 63075.527086 0.000000 601638.946912 0.000000 1653.713745 -EDGE_SE2 77 78 0.282617 0.095127 0.333053 11.189119 9.319517 0.000000 1124.510027 0.000000 1406.840866 -EDGE_SE2 78 79 0.636095 0.008032 -0.007625 11.207888 -4.778031 0.000000 247.011069 0.000000 2462.306663 -EDGE_SE2 79 80 0.646911 -0.030410 -0.077284 11.319895 -6.885926 0.000000 238.216160 0.000000 2154.168095 -EDGE_SE2 80 81 0.639697 -0.008063 -0.028569 11.170556 -3.722959 0.000000 244.273973 0.000000 2363.051282 -EDGE_SE2 81 82 0.643152 -0.022848 -0.050289 11.161415 -3.403565 0.000000 241.398318 0.000000 2266.325966 -EDGE_SE2 82 83 0.640259 -0.000745 -0.019030 11.185422 -4.158907 0.000000 243.868413 0.000000 2407.498744 -EDGE_SE2 83 84 0.642213 -0.028725 -0.071607 11.278239 -6.209353 0.000000 241.809620 0.000000 2177.051366 -EDGE_SE2 84 85 0.642807 -0.004171 0.013937 11.207431 4.714878 0.000000 241.906303 0.000000 2431.743719 -EDGE_SE2 85 86 0.729089 -0.020666 -0.079989 11.582543 -9.118938 0.000000 187.499441 0.000000 2143.389493 -EDGE_SE2 86 87 0.611674 -0.018501 -0.038112 11.126983 -2.015351 0.000000 267.015944 0.000000 2319.805566 -EDGE_SE2 87 88 0.363613 -0.001497 -0.025112 11.439512 -15.640496 0.000000 756.007915 0.000000 2379.016060 -EDGE_SE2 88 89 0.022194 0.007878 0.405075 748.400424 11505.714792 0.000000 179562.707200 0.000000 1266.312242 -EDGE_SE2 89 90 0.645333 -0.002553 -0.026790 11.230485 -5.227171 0.000000 239.999401 0.000000 2371.246746 -EDGE_SE2 90 91 0.653796 0.009633 0.053106 11.438992 8.540445 0.000000 233.567599 0.000000 2254.217590 -EDGE_SE2 91 92 0.637138 -0.022076 -0.111746 12.505303 -18.044302 0.000000 244.649107 0.000000 2022.687812 -EDGE_SE2 92 93 0.640542 -0.048819 -0.097619 11.218480 -4.981269 0.000000 242.212560 0.000000 2075.089230 -EDGE_SE2 93 94 0.639915 -0.019948 -0.040363 11.130823 -2.142336 0.000000 243.948392 0.000000 2309.777849 -EDGE_SE2 94 95 0.643361 0.058181 0.138081 11.634914 10.928304 0.000000 239.112551 0.000000 1930.161562 -EDGE_SE2 95 96 0.638452 0.002717 0.020015 11.169275 3.690420 0.000000 245.262988 0.000000 2402.851280 -EDGE_SE2 96 97 0.615807 -0.026362 -0.075608 11.382661 -8.269572 0.000000 262.946629 0.000000 2160.886525 -EDGE_SE2 97 98 0.610633 -0.021924 -0.063326 11.304343 -7.040699 0.000000 267.649507 0.000000 2211.093675 -EDGE_SE2 98 99 0.729556 0.014258 0.041080 11.193076 3.804772 0.000000 187.727053 0.000000 2306.597420 -EDGE_SE2 99 100 0.585696 -0.025742 -0.058133 11.167610 -3.975845 0.000000 290.892636 0.000000 2232.849702 -EDGE_SE2 100 101 0.637186 0.067759 0.095665 11.135663 -2.388768 0.000000 243.522972 0.000000 2082.497224 -EDGE_SE2 101 102 0.646556 -0.024441 -0.094339 11.838827 -12.853666 0.000000 238.145742 0.000000 2087.546965 -EDGE_SE2 102 103 0.640410 0.007435 0.107121 13.227361 22.089363 0.000000 241.679335 0.000000 2039.622675 -EDGE_SE2 103 104 0.644201 -0.014336 -0.024966 11.112805 -0.623830 0.000000 240.845479 0.000000 2379.693860 -EDGE_SE2 104 105 0.644960 0.019675 0.055427 11.253454 5.708380 0.000000 240.033921 0.000000 2244.313947 -EDGE_SE2 105 106 0.633327 -0.017685 -0.046638 11.194517 -4.454694 0.000000 249.035067 0.000000 2282.164848 -EDGE_SE2 106 107 0.647889 -0.007117 0.003228 11.156976 3.226972 0.000000 238.156676 0.000000 2483.937815 -EDGE_SE2 107 108 0.418841 0.012880 0.059022 11.557560 15.782621 0.000000 569.050200 0.000000 2229.102528 -EDGE_SE2 108 109 0.012870 -0.002240 -0.453333 45067.256701 -156114.787673 0.000000 540932.368601 0.000000 1183.612533 -EDGE_SE2 109 110 0.014179 -0.004043 -0.597121 45347.441263 -137112.106751 0.000000 414683.621097 0.000000 980.086413 -EDGE_SE2 110 111 0.096952 -0.046958 -0.510989 42.005133 -514.703903 0.000000 8586.236292 0.000000 1095.008280 -EDGE_SE2 111 112 0.662640 0.007778 0.052084 11.463505 8.729519 0.000000 227.358980 0.000000 2258.599235 -EDGE_SE2 112 113 0.647895 0.015723 0.044858 11.207376 4.673389 0.000000 237.990065 0.000000 2289.947176 -EDGE_SE2 113 114 0.639175 0.001049 0.034783 11.367673 7.738365 0.000000 244.514402 0.000000 2334.755667 -EDGE_SE2 114 115 0.643430 0.022360 0.055827 11.213458 4.852193 0.000000 241.150882 0.000000 2242.613753 -EDGE_SE2 115 116 0.763396 0.014434 0.039419 11.178609 3.289916 0.000000 171.464543 0.000000 2313.975233 -EDGE_SE2 116 117 0.634411 0.022615 0.090058 11.812568 12.875464 0.000000 247.444399 0.000000 2103.976068 -EDGE_SE2 117 118 0.031050 -0.001921 -0.343244 7981.193322 -27566.715976 0.000000 95358.161435 0.000000 1385.575483 -EDGE_SE2 118 119 0.498463 -0.026118 -0.058682 11.126767 -2.471741 0.000000 401.352854 0.000000 2230.534528 -EDGE_SE2 119 120 0.638636 0.019165 0.084147 11.796072 12.637674 0.000000 244.278828 0.000000 2126.981262 -EDGE_SE2 120 121 0.608883 0.022686 0.061480 11.262812 6.257264 0.000000 269.206349 0.000000 2218.790906 -EDGE_SE2 121 122 0.610979 0.006491 0.049908 11.507132 10.075663 0.000000 267.458443 0.000000 2267.971114 -EDGE_SE2 122 123 0.214919 0.006655 -0.018770 16.427458 -106.823784 0.000000 2157.570163 0.000000 2408.727735 -EDGE_SE2 123 124 0.224600 -0.105868 -0.436366 11.138335 6.622207 0.000000 1621.948711 0.000000 1211.740925 -EDGE_SE2 124 125 0.625260 -0.011376 -0.017225 11.111340 0.236437 0.000000 255.702505 0.000000 2416.050226 -EDGE_SE2 125 126 0.630905 0.083897 0.196975 12.098786 15.227356 0.000000 245.877115 0.000000 1744.897213 -EDGE_SE2 126 127 0.635911 -0.003633 -0.003082 11.112746 0.621349 0.000000 247.280806 0.000000 2484.660949 -EDGE_SE2 127 128 0.644637 0.020444 0.034153 11.112488 0.561814 0.000000 240.398060 0.000000 2337.601172 -EDGE_SE2 128 129 0.638546 -0.014303 -0.035619 11.152032 -3.094288 0.000000 245.089747 0.000000 2330.987741 -EDGE_SE2 129 130 0.640721 0.025473 0.048893 11.130575 2.125338 0.000000 243.187509 0.000000 2272.362609 -EDGE_SE2 130 131 0.641480 0.013548 0.083601 12.014929 14.445918 0.000000 242.003477 0.000000 2129.125269 -EDGE_SE2 131 132 0.641305 -0.014532 -0.055040 11.354232 -7.504896 0.000000 242.779959 0.000000 2245.960726 -EDGE_SE2 132 133 0.581934 -0.015905 -0.042094 11.173057 -4.193601 0.000000 295.010721 0.000000 2302.110777 -EDGE_SE2 133 134 0.610231 0.001805 -0.024124 11.299860 -6.968043 0.000000 268.350792 0.000000 2383.608476 -EDGE_SE2 134 135 0.579655 -0.017960 -0.033069 11.112368 -0.599782 0.000000 297.332685 0.000000 2342.509439 -EDGE_SE2 135 136 0.642725 0.014632 0.012040 11.137646 -2.474784 0.000000 241.922944 0.000000 2440.870018 -EDGE_SE2 136 137 0.634138 -0.020053 -0.051400 11.204026 -4.694831 0.000000 248.333522 0.000000 2261.538905 -EDGE_SE2 137 138 0.640742 0.028547 0.068532 11.244796 5.567274 0.000000 242.959321 0.000000 2189.600800 -EDGE_SE2 138 139 0.624343 0.022436 0.065016 11.318542 7.127247 0.000000 256.001043 0.000000 2204.081980 -EDGE_SE2 139 140 0.649355 0.026111 0.030256 11.133375 -2.241330 0.000000 236.751877 0.000000 2355.318828 -EDGE_SE2 140 141 0.633752 -0.015337 -0.048721 11.254069 -5.827843 0.000000 248.689278 0.000000 2273.108048 -EDGE_SE2 141 142 0.643523 0.009872 -0.004100 11.198132 -4.475923 0.000000 241.330701 0.000000 2479.625389 -EDGE_SE2 142 143 0.634003 -0.068517 -0.110892 11.113575 -0.760641 0.000000 245.906731 0.000000 2025.798896 -EDGE_SE2 143 144 0.367489 0.008323 0.017249 11.132342 -3.934021 0.000000 740.076637 0.000000 2415.936223 -EDGE_SE2 144 145 0.011506 -0.002421 -0.499034 59809.374609 -199183.039696 0.000000 663473.241646 0.000000 1112.543606 -EDGE_SE2 145 146 0.002065 0.000912 -0.593946 14068785.759218 -8838843.642003 0.000000 5553100.053245 0.000000 983.994793 -EDGE_SE2 146 147 0.052046 -0.024279 -0.487148 88.850566 -1532.993200 0.000000 30241.168070 0.000000 1130.398639 -EDGE_SE2 147 148 0.437634 -0.008022 -0.035943 11.269607 -8.996749 0.000000 521.795770 0.000000 2329.529896 -EDGE_SE2 148 149 0.649282 0.006558 0.024834 11.160187 3.330542 0.000000 237.137078 0.000000 2380.306915 -EDGE_SE2 149 150 0.638778 0.018547 0.013910 11.164529 -3.533262 0.000000 244.815913 0.000000 2431.874707 -EDGE_SE2 150 151 0.642396 0.027197 0.085399 11.539278 9.931167 0.000000 241.460866 0.000000 2122.077176 -EDGE_SE2 151 152 0.642196 -0.014560 -0.068180 11.589745 -10.509493 0.000000 241.870955 0.000000 2191.044127 -EDGE_SE2 152 153 0.641634 0.027219 0.085722 11.545124 10.011045 0.000000 242.028095 0.000000 2120.814737 -EDGE_SE2 153 154 0.638389 -0.020707 -0.077238 11.580742 -10.472604 0.000000 244.646718 0.000000 2154.352072 -EDGE_SE2 154 155 0.642162 0.011168 0.026427 11.130001 2.090263 0.000000 242.407116 0.000000 2372.924244 -EDGE_SE2 155 156 0.644865 0.009414 0.023665 11.129963 2.079071 0.000000 240.400517 0.000000 2385.746522 -EDGE_SE2 156 157 0.581283 -0.014428 -0.072363 11.754151 -13.514232 0.000000 295.128631 0.000000 2173.984116 -EDGE_SE2 157 158 0.187127 -0.000419 0.029090 13.902620 89.068131 0.000000 2852.990445 0.000000 2360.659192 -EDGE_SE2 158 159 -0.002775 0.000752 0.993417 10949150.533757 3540503.247990 0.000000 1144864.853964 0.000000 629.134778 -EDGE_SE2 159 160 0.010178 0.000761 1.042069 650920.894971 448555.873968 0.000000 309120.571532 0.000000 599.513799 -EDGE_SE2 160 161 -0.000005 0.000004 0.981942 2693538350855.096191 -157146640359.091309 0.000000 9168262482.076782 0.000000 636.440966 -EDGE_SE2 161 162 -0.015739 -0.012123 1.042202 35897.561333 88343.035344 0.000000 217488.511233 0.000000 599.435534 -EDGE_SE2 162 163 0.001603 0.001566 1.003233 1029828.017450 4408843.295789 0.000000 18875113.167768 0.000000 622.984264 -EDGE_SE2 163 164 0.014062 0.009080 0.929958 43510.337182 116762.574144 0.000000 313430.450998 0.000000 671.188169 -EDGE_SE2 164 165 0.127064 0.050581 0.402133 14.003612 124.194925 0.000000 5343.652150 0.000000 1271.632407 -EDGE_SE2 165 166 0.660048 0.003938 -0.000969 11.121614 -1.514549 0.000000 229.516161 0.000000 2495.162033 -EDGE_SE2 166 167 0.637952 -0.005107 -0.029173 11.216206 -4.964111 0.000000 245.589760 0.000000 2360.278446 -EDGE_SE2 167 168 0.609195 0.011564 0.012037 11.123559 -1.792903 0.000000 269.346120 0.000000 2440.884489 -EDGE_SE2 168 169 0.616410 -0.017912 -0.037053 11.127238 -2.015259 0.000000 262.946448 0.000000 2324.545784 -EDGE_SE2 169 170 0.607779 0.006983 -0.020916 11.383588 -8.405441 0.000000 270.404841 0.000000 2398.611924 -EDGE_SE2 170 171 0.584191 -0.014911 -0.038741 11.160361 -3.724488 0.000000 292.775082 0.000000 2316.996943 -EDGE_SE2 171 172 0.648836 0.010594 0.013474 11.112953 -0.645665 0.000000 237.471401 0.000000 2433.967559 -EDGE_SE2 172 173 0.642894 -0.013166 -0.018042 11.112478 0.561628 0.000000 241.844714 0.000000 2412.173920 -EDGE_SE2 173 174 0.638185 0.007116 0.045162 11.382152 7.965912 0.000000 245.229896 0.000000 2288.615243 -EDGE_SE2 174 175 0.625733 0.004082 -0.019946 11.282223 -6.462935 0.000000 255.218243 0.000000 2403.176400 -EDGE_SE2 175 176 0.613713 -0.013173 0.014287 11.435899 9.081745 0.000000 265.055874 0.000000 2430.067237 -EDGE_SE2 176 177 0.634525 0.002256 -0.022912 11.277271 -6.276557 0.000000 248.202540 0.000000 2389.260272 -EDGE_SE2 177 178 0.640137 -0.023037 -0.034183 11.111855 0.416076 0.000000 243.719928 0.000000 2337.465554 -EDGE_SE2 178 179 0.353790 0.008069 0.053221 11.839402 23.935910 0.000000 797.785636 0.000000 2253.725346 -EDGE_SE2 179 180 0.003152 -0.000263 -0.442165 1233046.693540 -3286666.439106 0.000000 8760647.410566 0.000000 1202.015605 -EDGE_SE2 180 181 0.557570 -0.008188 -0.051388 11.529199 -11.385701 0.000000 321.175409 0.000000 2261.590530 -EDGE_SE2 181 182 0.573085 -0.036151 -0.172968 14.630195 -31.871096 0.000000 299.756322 0.000000 1817.053357 -EDGE_SE2 182 183 0.603594 -0.027970 -0.056017 11.135892 -2.551709 0.000000 273.866587 0.000000 2241.806837 -EDGE_SE2 183 184 0.635433 -0.054532 -0.150813 12.107735 -15.262873 0.000000 244.855650 0.000000 1887.689196 -EDGE_SE2 184 185 0.634881 -0.022979 -0.096285 11.965079 -14.190439 0.000000 246.914669 0.000000 2080.142393 -EDGE_SE2 185 186 0.643298 -0.040128 -0.069768 11.123925 -1.715150 0.000000 240.694352 0.000000 2184.544034 -EDGE_SE2 186 187 0.616544 -0.013175 -0.025584 11.115593 -1.062453 0.000000 262.945790 0.000000 2376.826796 -EDGE_SE2 187 188 0.637286 0.000267 -0.008123 11.128264 -2.008140 0.000000 246.207666 0.000000 2459.874568 -EDGE_SE2 188 189 0.639354 -0.005159 -0.029399 11.217330 -4.979110 0.000000 244.512278 0.000000 2359.242182 -EDGE_SE2 189 190 0.641605 -0.016631 -0.026189 11.111129 -0.063557 0.000000 242.757543 0.000000 2374.025058 -EDGE_SE2 190 191 0.641101 -0.008160 -0.020962 11.126855 -1.911760 0.000000 243.247747 0.000000 2398.395787 -EDGE_SE2 191 192 0.634787 -0.009757 -0.024655 11.131543 -2.200448 0.000000 248.088013 0.000000 2381.138634 -EDGE_SE2 192 193 0.586234 -0.010454 -0.051260 11.423659 -9.345831 0.000000 290.571036 0.000000 2262.141300 -EDGE_SE2 193 194 0.611583 -0.006689 -0.021980 11.142360 -2.829372 0.000000 267.292453 0.000000 2393.620056 -EDGE_SE2 194 195 0.610567 -0.010284 -0.023227 11.121593 -1.641455 0.000000 268.159748 0.000000 2387.789433 -EDGE_SE2 195 196 0.641859 -0.011003 -0.041852 11.252480 -5.719563 0.000000 242.515471 0.000000 2303.180363 -EDGE_SE2 196 197 0.640092 -0.013813 -0.028233 11.121429 -1.549936 0.000000 243.946727 0.000000 2364.595903 -EDGE_SE2 197 198 0.639039 -0.009178 -0.058660 11.569437 -10.339579 0.000000 244.366482 0.000000 2230.627234 -EDGE_SE2 198 199 0.637088 -0.027408 -0.061598 11.192373 -4.367444 0.000000 245.840841 0.000000 2218.297682 -EDGE_SE2 199 200 0.636910 -0.008520 -0.021764 11.127669 -1.974000 0.000000 246.454469 0.000000 2394.632181 -EDGE_SE2 200 201 0.639616 -0.019900 -0.056243 11.258405 -5.857515 0.000000 244.050370 0.000000 2240.847600 -EDGE_SE2 201 202 0.573162 0.008125 0.017141 11.113691 0.869688 0.000000 304.336907 0.000000 2416.449299 -EDGE_SE2 202 203 0.807715 -0.017801 -0.055477 11.269967 -4.748397 0.000000 153.046283 0.000000 2244.101317 -EDGE_SE2 203 204 0.600516 -0.019464 -0.097088 12.222178 -17.152147 0.000000 275.898243 0.000000 2077.098438 -EDGE_SE2 204 205 0.607570 -0.009135 -0.005030 11.137105 2.598215 0.000000 270.811426 0.000000 2475.038492 -EDGE_SE2 205 206 0.587179 0.007336 0.006623 11.120721 -1.637028 0.000000 289.985432 0.000000 2467.211100 -EDGE_SE2 206 207 0.607993 0.006080 0.021126 11.143219 2.885684 0.000000 270.462940 0.000000 2397.625450 -EDGE_SE2 207 208 0.644034 -0.008545 -0.004095 11.130455 2.108903 0.000000 241.029670 0.000000 2479.650084 -EDGE_SE2 208 209 0.640840 0.009001 0.044393 11.325040 7.046915 0.000000 243.239179 0.000000 2291.986757 -EDGE_SE2 209 210 0.641153 -0.014043 -0.012923 11.129806 2.082671 0.000000 243.128297 0.000000 2436.616291 -EDGE_SE2 210 211 0.640990 0.006728 -0.001668 11.145470 -2.824640 0.000000 243.325777 0.000000 2491.680820 -EDGE_SE2 211 212 0.638573 -0.025254 -0.057210 11.184192 -4.132365 0.000000 244.776704 0.000000 2236.750195 -EDGE_SE2 212 213 0.648396 -0.008808 -0.024826 11.139763 -2.548475 0.000000 237.786398 0.000000 2380.344078 -EDGE_SE2 213 214 0.637242 -0.004643 -0.007684 11.111148 -0.093735 0.000000 246.245036 0.000000 2462.018335 -EDGE_SE2 214 215 0.369747 -0.004429 -0.039914 11.673090 -20.110851 0.000000 730.793592 0.000000 2311.772848 -EDGE_SE2 215 216 0.006980 -0.001179 -0.507763 222524.090867 -628114.036197 0.000000 1773063.824260 0.000000 1099.699039 -EDGE_SE2 216 217 -0.001832 0.001260 -0.551814 52174.391125 1025898.356469 0.000000 20176415.615022 0.000000 1038.151360 -EDGE_SE2 217 218 0.000862 -0.000506 -0.060277 20602967.870958 40459206.697150 0.000000 79452073.533188 0.000000 2223.828683 -EDGE_SE2 218 219 0.576874 -0.106568 -0.173874 11.132755 2.459345 0.000000 290.557594 0.000000 1814.249623 -EDGE_SE2 219 220 0.629125 -0.005523 -0.044144 11.413053 -8.534327 0.000000 252.332357 0.000000 2293.080041 -EDGE_SE2 220 221 0.642903 0.008921 0.051755 11.442103 8.733716 0.000000 241.563444 0.000000 2260.012484 -EDGE_SE2 221 222 0.635198 -0.000697 -0.024981 11.246132 -5.652071 0.000000 247.710771 0.000000 2379.624210 -EDGE_SE2 222 223 0.639045 0.029371 0.096256 11.701399 11.718901 0.000000 243.764798 0.000000 2080.252449 -EDGE_SE2 223 224 0.637940 -0.001297 -0.026485 11.251362 -5.734476 0.000000 245.578734 0.000000 2372.656095 -EDGE_SE2 224 225 0.639421 0.008657 0.048309 11.393218 8.109986 0.000000 244.256072 0.000000 2274.895125 -EDGE_SE2 225 226 0.638048 -0.023812 -0.051167 11.156122 -3.246372 0.000000 245.250378 0.000000 2262.541595 -EDGE_SE2 226 227 0.642744 0.047412 0.156718 12.692747 18.992206 0.000000 239.168545 0.000000 1868.465232 -EDGE_SE2 227 228 0.588969 -0.135551 -0.358747 15.698176 -34.406864 0.000000 269.191657 0.000000 1354.137035 -EDGE_SE2 228 229 0.605993 0.034684 0.124928 12.304340 17.583695 0.000000 270.228487 0.000000 1975.560427 -EDGE_SE2 229 230 0.370582 0.002463 -0.025443 11.849164 -22.992568 0.000000 727.398994 0.000000 2377.480475 -EDGE_SE2 230 231 -0.130796 -0.004868 0.073003 18.577316 208.431226 0.000000 5829.807352 0.000000 2171.391514 -EDGE_SE2 231 232 0.345343 -0.135465 -0.413759 12.252120 -28.551107 0.000000 725.536788 0.000000 1250.803404 -EDGE_SE2 232 233 0.649941 0.026872 0.109205 12.147339 15.241388 0.000000 235.289518 0.000000 2031.965694 -EDGE_SE2 233 234 0.647791 -0.001996 -0.038195 11.391127 -7.971100 0.000000 238.021188 0.000000 2319.434660 -EDGE_SE2 234 235 0.300180 0.002544 0.000515 11.180724 -8.744740 0.000000 1109.628316 0.000000 2497.426988 -EDGE_SE2 235 236 0.331863 0.149674 0.417637 11.138398 -4.503817 0.000000 754.488686 0.000000 1243.969525 -EDGE_SE2 236 237 0.654682 0.025212 0.076902 11.438281 8.513385 0.000000 232.640473 0.000000 2155.696624 -EDGE_SE2 237 238 0.648140 0.014417 -0.026834 11.656908 -11.112994 0.000000 237.383264 0.000000 2371.043534 -EDGE_SE2 238 239 0.643519 -0.017811 -0.061244 11.370468 -7.722173 0.000000 241.033805 0.000000 2219.777847 -EDGE_SE2 239 240 0.603843 -0.096900 -0.209505 11.761203 -12.890609 0.000000 266.717846 0.000000 1708.931569 -EDGE_SE2 240 241 0.584456 0.014283 0.092258 12.403890 19.031519 0.000000 291.281847 0.000000 2095.509047 -EDGE_SE2 241 242 0.612687 0.022692 0.027357 11.134913 -2.463133 0.000000 266.004463 0.000000 2368.630078 -EDGE_SE2 242 243 0.648066 -0.017400 -0.010559 11.171248 3.692755 0.000000 237.869261 0.000000 2448.029575 -EDGE_SE2 243 244 0.642215 0.026261 0.062075 11.214953 4.895996 0.000000 241.951020 0.000000 2216.305562 -EDGE_SE2 244 245 0.634243 -0.022273 -0.061989 11.282517 -6.373688 0.000000 248.115451 0.000000 2216.664530 -EDGE_SE2 245 246 0.645668 -0.028614 -0.079256 11.390140 -7.976362 0.000000 239.124210 0.000000 2146.303161 -EDGE_SE2 246 247 0.643529 0.022831 0.100014 12.068378 14.809059 0.000000 240.209522 0.000000 2066.063111 -EDGE_SE2 247 248 0.564321 0.027061 0.024967 11.270232 -6.932385 0.000000 313.133504 0.000000 2379.689217 -EDGE_SE2 248 249 -0.035940 0.003373 0.183988 5772.276933 20220.354842 0.000000 70979.863375 0.000000 1783.386223 -EDGE_SE2 249 250 0.007750 -0.001049 -0.606852 338497.920927 -662461.020100 0.000000 1296530.178991 0.000000 968.251297 -EDGE_SE2 250 251 0.463939 -0.175406 -0.437806 13.410741 -30.065645 0.000000 404.193089 0.000000 1209.314960 -EDGE_SE2 251 252 0.574959 0.003510 0.002433 11.115040 -1.069896 0.000000 302.485346 0.000000 2487.879253 -EDGE_SE2 252 253 0.605120 -0.005928 -0.017244 11.125640 -1.950811 0.000000 273.056569 0.000000 2415.959973 -EDGE_SE2 253 254 0.610735 -0.012632 -0.047846 11.300633 -6.974744 0.000000 267.794244 0.000000 2276.905934 -EDGE_SE2 254 255 0.044400 0.000523 0.074991 213.390433 3196.298492 0.000000 50517.134043 0.000000 2163.367754 -EDGE_SE2 255 256 0.001043 -0.000895 -0.499566 2299182.592246 10791888.202847 0.000000 50655150.120270 0.000000 1111.754353 -EDGE_SE2 256 257 0.555824 -0.061442 -0.099167 11.147977 3.373126 0.000000 319.742706 0.000000 2069.248487 -EDGE_SE2 257 258 0.629719 0.018359 0.091632 12.050310 15.010875 0.000000 251.024412 0.000000 2097.913089 -EDGE_SE2 258 259 0.636152 0.019457 0.038906 11.127473 1.964002 0.000000 246.855618 0.000000 2316.261026 -EDGE_SE2 259 260 0.591139 -0.005281 -0.010083 11.111475 -0.316152 0.000000 286.144813 0.000000 2450.337378 -EDGE_SE2 260 261 0.038207 -0.011731 -0.314328 28.012479 -1028.395525 0.000000 62585.773083 0.000000 1447.213112 -EDGE_SE2 261 262 0.655511 -0.012976 0.004878 11.245910 5.462837 0.000000 232.497259 0.000000 2475.787308 -EDGE_SE2 262 263 0.621841 0.001156 0.011526 11.134237 2.392264 0.000000 258.583295 0.000000 2443.351271 -EDGE_SE2 263 264 0.608889 0.019368 0.094641 12.130010 16.192201 0.000000 268.435238 0.000000 2086.395259 -EDGE_SE2 264 265 0.612314 0.007199 0.017955 11.120930 1.584091 0.000000 266.671128 0.000000 2412.586253 -EDGE_SE2 265 266 0.576085 -0.083302 -0.132058 11.148980 3.279437 0.000000 295.110014 0.000000 1950.754657 -EDGE_SE2 266 267 0.757425 -0.007866 -0.038469 11.239778 -4.580310 0.000000 174.161685 0.000000 2318.210856 -EDGE_SE2 267 268 0.631857 -0.080953 -0.120705 11.121739 1.581391 0.000000 246.417934 0.000000 1990.478036 -EDGE_SE2 268 269 0.641922 0.003817 0.021827 11.169502 3.676650 0.000000 242.613796 0.000000 2394.336911 -EDGE_SE2 269 270 0.637667 0.034307 0.104727 11.718968 11.913668 0.000000 244.612698 0.000000 2048.472187 -EDGE_SE2 270 271 0.640010 -0.062261 -0.119686 11.230091 -5.238185 0.000000 241.725444 0.000000 1994.102659 -EDGE_SE2 271 272 0.644232 0.019193 0.057497 11.287428 6.360389 0.000000 240.553533 0.000000 2235.536271 -EDGE_SE2 272 273 0.634342 0.083237 0.206754 12.465423 17.719715 0.000000 242.954542 0.000000 1716.732048 -EDGE_SE2 273 274 0.640984 0.007900 0.019834 11.124210 1.744119 0.000000 243.341574 0.000000 2403.704272 -EDGE_SE2 274 275 0.606472 -0.086361 -0.177559 11.443959 -9.213419 0.000000 266.144138 0.000000 1802.912528 -EDGE_SE2 275 276 0.612197 0.023588 0.108696 12.366721 17.860495 0.000000 265.168738 0.000000 2033.831865 -EDGE_SE2 276 277 0.583581 0.010361 -0.030920 11.779645 -13.724550 0.000000 292.866956 0.000000 2352.285755 -EDGE_SE2 277 278 0.636078 -0.067917 -0.095289 11.139759 2.584894 0.000000 244.345909 0.000000 2083.927264 -EDGE_SE2 278 279 0.642761 -0.012725 -0.054157 11.383584 -7.926158 0.000000 241.680475 0.000000 2249.724898 -EDGE_SE2 279 280 0.638781 -0.006089 0.003079 11.148313 2.949856 0.000000 245.014031 0.000000 2484.675811 -EDGE_SE2 280 281 0.641856 -0.029617 -0.099276 11.763757 -12.263888 0.000000 241.562200 0.000000 2068.838150 -EDGE_SE2 281 282 0.639782 0.004798 0.040856 11.370470 7.772433 0.000000 244.033931 0.000000 2307.590321 -EDGE_SE2 282 283 0.642050 0.012891 -0.006948 11.280026 -6.249342 0.000000 242.317369 0.000000 2465.618735 -EDGE_SE2 283 284 0.634635 -0.008598 0.028031 11.520810 9.848040 0.000000 247.830973 0.000000 2365.525243 -EDGE_SE2 284 285 0.644186 0.019368 0.016799 11.151476 -3.044364 0.000000 240.720053 0.000000 2418.075116 -EDGE_SE2 285 286 0.616883 0.003268 0.049122 11.594142 11.014881 0.000000 262.290847 0.000000 2271.370705 -EDGE_SE2 286 287 0.041606 0.000178 -0.109420 754.499701 -6510.220695 0.000000 57024.326077 0.000000 2031.178201 -EDGE_SE2 287 288 0.009415 -0.003373 -0.619963 74221.251106 -262085.361102 0.000000 925608.832783 0.000000 952.642204 -EDGE_SE2 288 289 0.020008 -0.006408 -0.604589 19113.152514 -62948.109898 0.000000 207447.816761 0.000000 970.984702 -EDGE_SE2 289 290 0.454169 -0.104092 -0.231282 11.127187 -2.688060 0.000000 460.591382 0.000000 1649.016296 -EDGE_SE2 290 291 0.647578 0.004260 0.009723 11.113360 0.715048 0.000000 238.447481 0.000000 2452.084944 -EDGE_SE2 291 292 0.634089 -0.015008 -0.055281 11.348399 -7.502724 0.000000 248.336711 0.000000 2244.935000 -EDGE_SE2 292 293 0.642557 -0.005982 -0.023777 11.159473 -3.342559 0.000000 242.132375 0.000000 2385.224555 -EDGE_SE2 293 294 0.639112 0.001322 -0.000108 11.112218 -0.508677 0.000000 244.817748 0.000000 2499.460087 -EDGE_SE2 294 295 0.640372 -0.027705 -0.113609 12.259570 -16.292856 0.000000 242.253178 0.000000 2015.925806 -EDGE_SE2 295 296 0.642975 -0.021060 -0.046516 11.154844 -3.174767 0.000000 241.583458 0.000000 2282.696976 -EDGE_SE2 296 297 0.642345 0.000782 -0.012863 11.156958 -3.255777 0.000000 242.314814 0.000000 2436.904980 -EDGE_SE2 297 298 0.647985 0.003784 0.003363 11.112504 -0.562400 0.000000 238.150885 0.000000 2483.269445 -EDGE_SE2 298 299 0.612845 -0.007635 0.065661 12.664708 19.847274 0.000000 264.661036 0.000000 2201.414711 -EDGE_SE2 299 300 0.612360 0.028900 0.046427 11.111248 -0.186667 0.000000 266.084327 0.000000 2283.085285 -EDGE_SE2 300 301 0.590205 -0.014952 -0.054929 11.352681 -8.158527 0.000000 286.648280 0.000000 2246.433393 -EDGE_SE2 301 302 0.327130 -0.001110 -0.017014 11.282416 -12.575459 0.000000 934.273069 0.000000 2417.052846 -EDGE_SE2 302 303 0.000000 0.000000 0.007958 11.135739 3.094647 0.000000 399.975372 0.000000 2460.679983 -EDGE_SE2 303 304 0.531735 -0.000572 0.013349 11.182383 4.940694 0.000000 353.608097 0.000000 2434.568072 -EDGE_SE2 304 305 0.632029 0.091742 0.189082 11.583394 10.503320 0.000000 244.699503 0.000000 1768.138981 -EDGE_SE2 305 306 0.638032 0.009278 -0.014535 11.309292 -6.814055 0.000000 245.399171 0.000000 2428.879337 -EDGE_SE2 306 307 0.649045 -0.016359 -0.033059 11.125080 -1.777236 0.000000 237.218596 0.000000 2342.554790 -EDGE_SE2 307 308 0.638862 -0.008726 -0.051832 11.451746 -8.918684 0.000000 244.624962 0.000000 2259.681604 -EDGE_SE2 308 309 0.645288 0.030453 0.096996 11.678208 11.369540 0.000000 239.055109 0.000000 2077.446846 -EDGE_SE2 309 310 0.636777 0.000884 -0.032322 11.378630 -7.932902 0.000000 246.350008 0.000000 2345.900799 -EDGE_SE2 310 311 0.290424 -0.002112 0.179746 51.710880 214.552149 0.000000 1144.926065 0.000000 1796.234285 -EDGE_SE2 311 312 0.007354 0.003264 1.002917 471360.416969 711283.404228 0.000000 1073363.876974 0.000000 623.180856 -EDGE_SE2 312 313 0.200119 0.102327 0.503683 13.003444 61.001684 0.000000 1977.575148 0.000000 1105.674845 -EDGE_SE2 313 314 0.633848 0.018391 0.043519 11.161147 3.447475 0.000000 248.643057 0.000000 2295.827675 -EDGE_SE2 314 315 0.633704 0.002276 -0.000875 11.115856 -1.062415 0.000000 249.007791 0.000000 2495.630735 -EDGE_SE2 315 316 0.639305 0.015820 0.052631 11.292626 6.506496 0.000000 244.340479 0.000000 2256.252482 -EDGE_SE2 316 317 0.637745 0.004302 0.011142 11.115650 1.032197 0.000000 245.854624 0.000000 2445.207439 -EDGE_SE2 317 318 0.636745 0.035394 0.095957 11.494620 9.481044 0.000000 245.500106 0.000000 2081.387677 -EDGE_SE2 318 319 0.348842 0.011538 0.072712 12.383431 32.072340 0.000000 819.582938 0.000000 2172.569763 -EDGE_SE2 319 320 0.000816 -0.000527 0.973228 106005797.819726 2536098.274165 0.000000 60685.105012 0.000000 642.074570 -EDGE_SE2 320 321 0.006777 0.006256 1.044793 102222.634261 331234.073682 0.000000 1073432.269379 0.000000 597.917382 -EDGE_SE2 321 322 0.006473 0.002839 1.001084 615262.184536 923437.444301 0.000000 1386009.040037 0.000000 624.323050 -EDGE_SE2 322 323 0.016353 0.013170 0.997277 22353.154021 67589.307695 0.000000 204482.767224 0.000000 626.705357 -EDGE_SE2 323 324 0.008916 0.001230 0.663199 311347.556233 536104.854899 0.000000 923155.252921 0.000000 903.756801 -EDGE_SE2 324 325 0.003144 -0.000405 -0.524891 1487579.272379 -3549001.141685 0.000000 8467125.043520 0.000000 1075.133530 -EDGE_SE2 325 326 0.023808 -0.007961 -0.592174 11258.329132 -40719.337055 0.000000 147431.069280 0.000000 986.186273 -EDGE_SE2 326 327 0.020978 -0.009992 -0.620226 5671.563195 -31879.996101 0.000000 179561.107529 0.000000 952.332958 -EDGE_SE2 327 328 0.643658 -0.034894 -0.045241 11.129369 2.047184 0.000000 240.647976 0.000000 2288.269306 -EDGE_SE2 328 329 0.649334 -0.010852 -0.054672 11.436629 -8.570843 0.000000 236.780423 0.000000 2247.528337 -EDGE_SE2 329 330 0.639632 -0.008474 -0.018872 11.118489 -1.311825 0.000000 244.371181 0.000000 2408.245480 -EDGE_SE2 330 331 0.641038 0.003713 -0.014179 11.203728 -4.636800 0.000000 243.249680 0.000000 2430.584821 -EDGE_SE2 331 332 0.640252 -0.011677 -0.018427 11.111120 -0.044254 0.000000 243.867115 0.000000 2410.350498 -EDGE_SE2 332 333 0.177633 -0.001729 0.065170 28.796073 235.654693 0.000000 3151.244188 0.000000 2203.444704 -EDGE_SE2 333 334 0.000905 -0.002029 1.057518 13067665.297415 -9690930.296947 0.000000 7186773.836950 0.000000 590.544626 -EDGE_SE2 334 335 0.024703 0.015296 0.997066 21742.343151 45843.877395 0.000000 96722.659299 0.000000 626.837793 -EDGE_SE2 335 336 0.010478 0.002030 0.946908 412732.144616 438156.323325 0.000000 465170.257567 0.000000 659.552164 -EDGE_SE2 336 337 0.008745 0.002954 0.985008 440385.721295 568301.950425 0.000000 733402.863015 0.000000 634.476419 -EDGE_SE2 337 338 -0.003685 -0.001824 0.981724 1470665.482891 2556461.697178 0.000000 4443948.812959 0.000000 636.580801 -EDGE_SE2 338 339 -0.005129 -0.003808 1.041677 377018.548764 884152.776785 0.000000 2073514.322517 0.000000 599.744033 -EDGE_SE2 339 340 0.010570 0.010289 1.011780 25946.779143 106050.417947 0.000000 433649.108522 0.000000 617.702041 -EDGE_SE2 340 341 0.113717 0.080150 0.628571 12.212286 75.337385 0.000000 5165.350612 0.000000 942.598218 -EDGE_SE2 341 342 0.654766 0.022058 0.099815 12.080273 14.632015 0.000000 232.019342 0.000000 2066.810844 -EDGE_SE2 342 343 0.628741 0.054742 0.130801 11.574390 10.533194 0.000000 250.595866 0.000000 1955.093991 -EDGE_SE2 343 344 0.635892 -0.007155 -0.010075 11.111438 0.277943 0.000000 247.273507 0.000000 2450.376193 -EDGE_SE2 344 345 0.267580 0.003485 -0.027538 13.388942 -56.127772 0.000000 1394.149289 0.000000 2367.795687 -EDGE_SE2 345 346 0.004489 0.000038 -0.647423 1844936.688291 -2397918.213433 0.000000 3116674.368121 0.000000 921.148732 -EDGE_SE2 346 347 0.072838 -0.046842 -0.558829 13.253512 168.933111 0.000000 13331.862665 0.000000 1028.828663 -EDGE_SE2 347 348 0.589079 -0.006098 -0.016843 11.122785 -1.798313 0.000000 288.130205 0.000000 2417.865855 -EDGE_SE2 348 349 0.616820 -0.017333 -0.040458 11.149561 -3.109556 0.000000 262.589175 0.000000 2309.356075 -EDGE_SE2 349 350 0.785503 -0.000917 -0.019918 11.164179 -2.829897 0.000000 162.017193 0.000000 2403.308352 -EDGE_SE2 350 351 0.270645 -0.005037 -0.029292 11.265595 -14.459903 0.000000 1364.581559 0.000000 2359.732718 -EDGE_SE2 351 352 0.002244 -0.000330 -0.288296 389945.087215 -2724716.373664 0.000000 19039335.129753 0.000000 1506.290344 -EDGE_SE2 352 353 0.003402 -0.001192 -0.665425 800995.211276 -2349889.351851 0.000000 6894005.592158 0.000000 901.342500 -EDGE_SE2 353 354 -0.005763 0.001670 -0.603397 277124.929036 -832459.339385 0.000000 2500747.295676 0.000000 972.428940 -EDGE_SE2 354 355 0.000000 0.000000 -0.720990 180.577269 -192.833418 0.000000 230.533842 0.000000 844.079125 -EDGE_SE2 355 356 0.003943 -0.001205 -0.575253 444990.541595 -1555501.608157 0.000000 5437532.684522 0.000000 1007.486830 -EDGE_SE2 356 357 0.020153 -0.008599 -0.653072 12735.537924 -49883.324785 0.000000 195567.746252 0.000000 914.863854 -EDGE_SE2 357 358 0.015309 -0.003110 -0.615454 66643.110857 -151211.449053 0.000000 343163.086320 0.000000 957.967591 -EDGE_SE2 358 359 0.006974 -0.000995 -0.614029 417035.012297 -816381.545249 0.000000 1598190.077659 0.000000 959.659886 -EDGE_SE2 359 360 0.004457 -0.000580 -0.176301 10913.841058 -232052.237339 0.000000 4938979.710352 0.000000 1806.770854 -EDGE_SE2 360 361 0.010594 0.005702 0.919376 117786.647020 259806.659966 0.000000 573130.987341 0.000000 678.609427 -EDGE_SE2 361 362 0.219803 0.130838 0.533743 11.126432 -4.821230 0.000000 1528.288566 0.000000 1062.759073 -EDGE_SE2 362 363 0.297072 -0.003532 -0.006476 11.143964 6.070793 0.000000 1132.926894 0.000000 2467.931845 -EDGE_SE2 363 364 0.289348 0.182399 0.614616 13.404127 43.923133 0.000000 852.466620 0.000000 958.962236 -EDGE_SE2 364 365 0.292841 -0.019896 -0.497082 210.238012 -435.053006 0.000000 961.616130 0.000000 1115.446721 -EDGE_SE2 365 366 0.158985 -0.083838 -0.554071 25.686079 -211.524041 0.000000 3080.923734 0.000000 1035.138105 -EDGE_SE2 366 367 0.639497 -0.004946 0.002087 11.133620 2.291973 0.000000 244.487349 0.000000 2489.597576 -EDGE_SE2 367 368 0.604131 -0.012617 -0.052944 11.381139 -8.419024 0.000000 273.602223 0.000000 2254.911286 -EDGE_SE2 368 369 0.002209 0.000313 -0.259186 3043052.869717 -7202482.111400 0.000000 17047344.890980 0.000000 1576.740546 -EDGE_SE2 369 370 0.005991 -0.002050 -0.599321 177021.973379 -640449.340665 0.000000 2317243.809168 0.000000 977.391885 -EDGE_SE2 370 371 0.006708 -0.002639 -0.557206 63344.214539 -343349.901593 0.000000 1861425.577547 0.000000 1030.974377 -EDGE_SE2 371 372 0.558575 -0.019962 -0.032348 11.114630 1.042696 0.000000 320.094134 0.000000 2345.782636 -EDGE_SE2 372 373 0.602488 0.010152 -0.002327 11.208284 -5.066873 0.000000 275.312725 0.000000 2488.405486 -EDGE_SE2 373 374 0.632591 -0.017325 -0.065949 11.465862 -9.193251 0.000000 249.351067 0.000000 2200.225307 -EDGE_SE2 374 375 0.469417 0.004030 -0.028771 11.728554 -16.521047 0.000000 453.167816 0.000000 2362.123399 -EDGE_SE2 375 376 0.002158 0.000483 0.698524 4333313.980583 8354996.990813 0.000000 16109195.449061 0.000000 866.555999 -EDGE_SE2 376 377 0.046225 0.038326 0.699019 12.380728 187.607270 0.000000 27733.237753 0.000000 866.051140 -EDGE_SE2 377 378 0.665310 0.013616 0.055080 11.368301 7.426696 0.000000 225.566926 0.000000 2245.790433 -EDGE_SE2 378 379 0.642743 0.038423 0.085729 11.266862 5.984327 0.000000 241.043246 0.000000 2120.787390 -EDGE_SE2 379 380 0.640645 0.038346 0.120298 11.958441 13.985039 0.000000 241.931786 0.000000 1991.924564 -EDGE_SE2 380 381 0.233459 0.003584 0.150906 44.408710 244.130938 0.000000 1801.027395 0.000000 1887.384136 -EDGE_SE2 381 382 0.006327 0.000255 1.053123 1795131.477569 1120171.329981 0.000000 699008.143264 0.000000 593.075621 -EDGE_SE2 382 383 -0.003556 -0.002021 0.980056 1193066.389244 2388759.272445 0.000000 4782832.968807 0.000000 637.653764 -EDGE_SE2 383 384 0.001991 0.002244 0.957091 138704.428768 1233640.966374 0.000000 10972926.458664 0.000000 652.706547 -EDGE_SE2 384 385 0.011270 0.001792 1.022982 445019.439592 379059.233315 0.000000 322894.736351 0.000000 610.880091 -EDGE_SE2 385 386 0.168577 0.055826 0.222392 40.994230 -305.838725 0.000000 3141.216954 0.000000 1673.088872 -EDGE_SE2 386 387 0.606264 0.162988 0.328749 12.170230 15.994975 0.000000 252.669738 0.000000 1415.970180 -EDGE_SE2 387 388 0.635832 0.013644 0.010758 11.138130 -2.525694 0.000000 247.211302 0.000000 2447.065724 -EDGE_SE2 388 389 0.627947 -0.024187 -0.080320 11.534345 -10.113978 0.000000 252.803888 0.000000 2142.077483 -EDGE_SE2 389 390 0.069191 0.001300 0.478702 4122.849667 8300.847325 0.000000 16769.002054 0.000000 1143.348663 -EDGE_SE2 390 391 -0.133725 -0.033239 0.382997 112.537800 723.030020 0.000000 5165.300931 0.000000 1307.066045 -EDGE_SE2 391 392 -0.002743 0.000191 1.047762 10690557.469801 5209631.734700 0.000000 2538727.272155 0.000000 596.185006 -EDGE_SE2 392 393 0.028217 0.013447 1.259453 54184.105027 51083.362632 0.000000 48181.052425 0.000000 489.703700 -EDGE_SE2 393 394 0.008510 0.003621 0.998557 368727.424224 543264.764209 0.000000 800454.686659 0.000000 625.902660 -EDGE_SE2 394 395 -0.234595 -0.069505 0.339597 15.518106 85.399492 0.000000 1665.996927 0.000000 1393.130101 -EDGE_SE2 395 396 0.000000 0.000000 0.001250 11.111719 0.486111 0.000000 399.999392 0.000000 2493.761699 -EDGE_SE2 396 397 0.001351 -0.000419 -0.009641 4125762.827775 13757530.022207 0.000000 45875198.303653 0.000000 2452.483262 -EDGE_SE2 397 398 0.004038 0.000754 0.199105 1257.017158 85923.998064 0.000000 5925765.672764 0.000000 1738.703710 -EDGE_SE2 398 399 0.122070 0.031296 0.300741 26.669772 312.344207 0.000000 6281.503348 0.000000 1477.604991 -EDGE_SE2 399 400 0.657179 0.003449 0.051415 11.580586 10.161892 0.000000 231.067499 0.000000 2261.474377 -EDGE_SE2 400 401 0.635899 -0.025106 -0.091900 11.758968 -12.342900 0.000000 246.266720 0.000000 2096.883376 -EDGE_SE2 401 402 0.629497 -0.118990 -0.266463 12.583010 -18.442000 0.000000 242.178169 0.000000 1558.672941 -EDGE_SE2 402 403 0.633089 -0.005208 -0.033694 11.265698 -6.068382 0.000000 249.328787 0.000000 2339.677603 -EDGE_SE2 403 404 0.592291 -0.016693 -0.078703 11.809289 -13.806384 0.000000 284.130876 0.000000 2148.504341 -EDGE_SE2 404 405 0.003136 0.000509 0.534523 1319098.360620 3365183.519520 0.000000 8585083.951642 0.000000 1061.678944 -EDGE_SE2 405 406 -0.004868 -0.003220 0.979360 434468.323030 1042340.456046 0.000000 2500772.052588 0.000000 638.102476 -EDGE_SE2 406 407 0.360175 0.041381 0.128315 11.256473 10.438221 0.000000 760.666018 0.000000 1963.718742 -EDGE_SE2 407 408 0.616703 -0.006846 -0.037807 11.290664 -6.721434 0.000000 262.722906 0.000000 2321.169297 -EDGE_SE2 408 409 0.297889 -0.008429 -0.099428 16.743853 -79.045672 0.000000 1120.378773 0.000000 2068.266140 -EDGE_SE2 409 410 0.004317 -0.001082 -0.627510 701653.157370 -1746561.647658 0.000000 4347637.661335 0.000000 943.827609 -EDGE_SE2 410 411 -0.000994 0.000097 -0.588953 22378715.073239 -41773418.211876 0.000000 77976755.075261 0.000000 990.188564 -EDGE_SE2 411 412 0.546073 -0.101761 -0.202851 11.219546 -5.824669 0.000000 323.987402 0.000000 1727.890996 -EDGE_SE2 412 413 0.631438 -0.020731 -0.079531 11.633150 -11.167657 0.000000 250.014003 0.000000 2145.209801 -EDGE_SE2 413 414 0.633214 0.018368 0.103733 12.438356 17.726525 0.000000 247.864474 0.000000 2052.163475 -EDGE_SE2 414 415 0.642786 -0.007808 0.006683 11.192966 4.346517 0.000000 241.911433 0.000000 2466.917009 -EDGE_SE2 415 416 0.306053 0.007945 -0.055552 18.109521 -85.672115 0.000000 1059.879484 0.000000 2243.782429 -EDGE_SE2 416 417 0.267976 -0.110772 -0.425050 12.399497 -38.940001 0.000000 1188.028820 0.000000 1231.061654 -EDGE_SE2 417 418 0.438509 -0.005278 -0.045468 11.679675 -16.999880 0.000000 519.402521 0.000000 2287.275721 -EDGE_SE2 418 419 -0.008030 -0.002982 0.430439 7637.313369 101662.498186 0.000000 1355241.825942 0.000000 1221.803385 -EDGE_SE2 419 420 -0.065315 -0.007710 0.215762 233.503005 2255.992653 0.000000 22896.400499 0.000000 1691.386574 -EDGE_SE2 420 421 -0.013305 -0.007156 0.966654 91010.544219 177739.023434 0.000000 347168.883115 0.000000 646.374313 -EDGE_SE2 421 422 -0.003762 0.002250 1.237922 4986989.532826 -1042930.375544 0.000000 218119.888862 0.000000 499.171886 -EDGE_SE2 422 423 0.004840 0.001590 0.345136 2976.169439 106843.491501 0.000000 3850030.373965 0.000000 1381.680463 -EDGE_SE2 423 424 0.000000 0.000000 0.000279 11.111141 0.108500 0.000000 399.999970 0.000000 2498.605584 -EDGE_SE2 424 425 -0.001184 -0.000773 0.011635 14427656.748816 -22661090.484365 0.000000 35593138.003454 0.000000 2442.824774 -EDGE_SE2 425 426 0.000000 0.000000 -0.009217 11.144147 -3.584186 0.000000 399.966964 0.000000 2454.544407 -EDGE_SE2 426 427 0.032570 0.000297 0.003027 14.602102 -573.593983 0.000000 94256.571445 0.000000 2484.933444 -EDGE_SE2 427 428 0.662478 0.017221 -0.005659 11.327981 -6.850147 0.000000 227.483295 0.000000 2471.943383 -EDGE_SE2 428 429 0.646109 -0.008556 -0.041027 11.287389 -6.342667 0.000000 239.327268 0.000000 2306.832289 -EDGE_SE2 429 430 0.343414 -0.005292 -0.046373 11.913023 -25.889333 0.000000 846.935174 0.000000 2283.320937 -EDGE_SE2 430 431 -0.023101 -0.000669 0.051637 107.302578 4242.658469 0.000000 187139.464787 0.000000 2260.519686 -EDGE_SE2 431 432 0.009902 -0.002457 -0.632717 138557.863737 -337512.999974 0.000000 822224.717657 0.000000 937.817169 -EDGE_SE2 432 433 0.001378 -0.000302 -0.678362 9999210.149914 -20053649.036543 0.000000 40218116.393371 0.000000 887.500758 -EDGE_SE2 433 434 0.513100 -0.123605 -0.228760 11.131390 2.656033 0.000000 358.981365 0.000000 1655.792374 -EDGE_SE2 434 435 0.631214 0.005719 -0.028704 11.453001 -9.049106 0.000000 250.621585 0.000000 2362.431102 -EDGE_SE2 435 436 0.631793 -0.021639 -0.009165 11.261393 5.992726 0.000000 250.081133 0.000000 2454.797368 -EDGE_SE2 436 437 0.639424 0.009664 0.007564 11.124412 -1.761949 0.000000 244.511544 0.000000 2462.604819 -EDGE_SE2 437 438 0.468926 -0.010782 -0.032675 11.152708 -4.294523 0.000000 454.487167 0.000000 2344.297271 -EDGE_SE2 438 439 0.003173 -0.000464 -0.440138 821397.131579 -2704073.669587 0.000000 8902055.008072 0.000000 1205.401670 -EDGE_SE2 439 440 -0.014852 0.005433 -0.648635 34474.470288 -112210.861458 0.000000 365363.698028 0.000000 919.794858 -EDGE_SE2 440 441 -0.024049 0.006849 -0.627372 18805.328328 -51499.965243 0.000000 141131.456239 0.000000 943.987688 -EDGE_SE2 441 442 -0.014780 0.003839 -0.634781 59210.969468 -147922.954315 0.000000 369626.867304 0.000000 935.450222 -EDGE_SE2 442 443 -0.000800 0.000601 -0.571864 520464.172419 7194009.672200 0.000000 99439862.677541 0.000000 1011.835875 -EDGE_SE2 443 444 0.017737 -0.005934 -0.596674 20918.075426 -74425.493858 0.000000 264954.124953 0.000000 980.635254 -EDGE_SE2 444 445 0.013295 -0.004859 -0.663772 47441.842994 -146367.463524 0.000000 451689.453992 0.000000 903.134403 -EDGE_SE2 445 446 0.005858 0.000522 0.198590 34655.344042 314604.971132 0.000000 2856945.136973 0.000000 1740.198174 -EDGE_SE2 446 447 0.027440 0.012672 0.626113 4057.920343 20653.549968 0.000000 105419.866954 0.000000 945.449998 -EDGE_SE2 447 448 0.642139 0.024176 0.015042 11.228997 -5.217769 0.000000 242.055366 0.000000 2426.453558 -EDGE_SE2 448 449 0.651924 0.033077 0.098456 11.620735 10.662081 0.000000 234.177343 0.000000 2071.928088 -EDGE_SE2 449 450 0.646061 0.005408 0.011249 11.113005 0.657701 0.000000 239.562562 0.000000 2444.690013 -EDGE_SE2 450 451 0.475342 0.014049 0.039952 11.157786 4.485326 0.000000 442.142124 0.000000 2311.603906 -EDGE_SE2 451 452 0.003128 0.000025 -0.382848 1482988.188246 -3599772.040321 0.000000 8738081.943140 0.000000 1307.347729 -EDGE_SE2 452 453 -0.001414 0.000044 -0.628930 15847694.024322 -23260624.874036 0.000000 34141069.617498 0.000000 942.182786 -EDGE_SE2 453 454 0.248647 -0.103850 -0.427200 12.471635 -43.090213 0.000000 1375.854801 0.000000 1227.355391 -EDGE_SE2 454 455 0.599080 -0.006587 -0.019767 11.131695 -2.346400 0.000000 278.577271 0.000000 2404.020135 -EDGE_SE2 455 456 0.632985 -0.015395 -0.063626 11.479192 -9.358780 0.000000 249.066485 0.000000 2209.846555 -EDGE_SE2 456 457 0.357560 -0.010532 -0.086657 13.629849 -43.977817 0.000000 778.975316 0.000000 2117.166652 -EDGE_SE2 457 458 0.008700 -0.003028 -0.643446 108644.728053 -340906.127357 0.000000 1069817.962261 0.000000 925.612330 -EDGE_SE2 458 459 -0.005152 0.003223 -0.605857 5968.917352 -126872.556203 0.000000 2701785.030428 0.000000 969.451909 -EDGE_SE2 459 460 0.416054 -0.104238 -0.255576 11.165314 -5.371986 0.000000 543.523585 0.000000 1585.820389 -EDGE_SE2 460 461 0.649228 -0.030811 -0.086883 11.462229 -8.893307 0.000000 236.365424 0.000000 2116.286282 -EDGE_SE2 461 462 0.546102 -0.010087 -0.039056 11.248462 -6.670465 0.000000 335.062438 0.000000 2315.592315 -EDGE_SE2 462 463 0.001368 -0.000392 0.843270 40115968.021050 19291406.563907 0.000000 9277076.794710 0.000000 735.803923 -EDGE_SE2 463 464 0.219986 0.165070 0.680690 12.900768 48.403186 0.000000 1320.227268 0.000000 885.043825 -EDGE_SE2 464 465 0.606621 0.010649 0.008756 11.131273 -2.291927 0.000000 271.643258 0.000000 2456.788366 -EDGE_SE2 465 466 0.582724 -0.019176 -0.054453 11.242627 -6.100006 0.000000 294.042673 0.000000 2248.462015 -EDGE_SE2 466 467 0.609463 -0.011568 -0.042219 11.250443 -5.994134 0.000000 268.982117 0.000000 2301.558596 -EDGE_SE2 467 468 0.645554 -0.004365 -0.036329 11.311111 -6.762186 0.000000 239.747111 0.000000 2327.794866 -EDGE_SE2 468 469 0.640915 -0.033457 -0.083791 11.342903 -7.324322 0.000000 242.550344 0.000000 2128.378819 -EDGE_SE2 469 470 0.496055 0.004661 0.018154 11.141432 3.461691 0.000000 406.321439 0.000000 2411.643257 -EDGE_SE2 470 471 0.003172 -0.000201 -0.200803 186163.578620 -1344733.466553 0.000000 9714134.809108 0.000000 1733.789946 -EDGE_SE2 471 472 0.023951 -0.007826 -0.634338 15457.850073 -46841.273730 0.000000 142054.355974 0.000000 935.957765 -EDGE_SE2 472 473 0.005795 -0.000612 -0.642279 770586.651464 -1294281.400636 0.000000 2173924.317941 0.000000 926.928274 -EDGE_SE2 473 474 0.006655 -0.002332 -0.633006 171083.550792 -560999.777087 0.000000 1839703.994891 0.000000 937.485259 -EDGE_SE2 474 475 0.004438 -0.002279 -0.575983 41353.024051 -405427.745271 0.000000 3975919.455633 0.000000 1006.553705 -EDGE_SE2 475 476 0.004920 -0.000853 -0.653637 861490.486597 -1647075.461555 0.000000 3149079.624245 0.000000 914.238796 -EDGE_SE2 476 477 -0.005593 0.002916 -0.561690 16496.747941 -202882.586381 0.000000 2496811.464145 0.000000 1025.062106 -EDGE_SE2 477 478 -0.008770 0.002879 -0.629412 110767.500374 -343119.326612 0.000000 1062982.494329 0.000000 941.625450 -EDGE_SE2 478 479 -0.005316 0.000950 -0.456182 260653.569609 -908664.641767 0.000000 3167842.768150 0.000000 1178.986119 -EDGE_SE2 479 480 -0.002143 -0.000584 0.559864 1701134.587605 5621159.573829 0.000000 18574462.284739 0.000000 1027.463821 -EDGE_SE2 480 481 0.016780 0.006185 0.998459 113112.243905 150237.129574 0.000000 199577.592411 0.000000 625.964239 -EDGE_SE2 481 482 0.002129 0.000684 0.334515 11133.789831 471436.097728 0.000000 19981887.764379 0.000000 1403.760085 -EDGE_SE2 482 483 0.000000 0.000000 -0.006313 11.126610 -2.454990 0.000000 399.984501 0.000000 2468.731408 -EDGE_SE2 483 484 0.461514 0.003388 0.034531 11.449878 12.456397 0.000000 469.130063 0.000000 2335.893245 -EDGE_SE2 484 485 0.630348 0.014297 -0.002799 11.267128 -6.122690 0.000000 251.389266 0.000000 2486.063539 -EDGE_SE2 485 486 0.640080 -0.006164 0.008991 11.191872 4.336635 0.000000 243.975902 0.000000 2455.644098 -EDGE_SE2 486 487 0.638592 0.022157 0.027672 11.122603 -1.639115 0.000000 244.911905 0.000000 2367.178245 -EDGE_SE2 487 488 0.641671 0.002950 0.035457 11.331743 7.147283 0.000000 242.644669 0.000000 2331.717176 -EDGE_SE2 488 489 0.486254 0.015193 0.029736 11.112036 -0.616989 0.000000 422.520775 0.000000 2357.698224 -EDGE_SE2 489 490 0.004012 0.001331 0.483683 148092.465768 898284.334868 0.000000 5449142.422335 0.000000 1135.684680 -EDGE_SE2 490 491 0.003142 0.002440 0.933695 460500.560493 1642380.154927 0.000000 5857718.767430 0.000000 668.596440 -EDGE_SE2 491 492 0.234443 0.072984 0.301949 11.111148 0.245247 0.000000 1658.639702 0.000000 1474.864302 -EDGE_SE2 492 493 0.622117 -0.019196 -0.055751 11.264294 -6.149470 0.000000 257.979045 0.000000 2242.936641 -EDGE_SE2 493 494 0.632902 -0.009810 -0.061610 11.617811 -10.980862 0.000000 249.080844 0.000000 2218.247533 -EDGE_SE2 494 495 0.635286 0.054465 0.110803 11.261154 5.934337 0.000000 245.819252 0.000000 2026.123532 -EDGE_SE2 495 496 0.641209 0.012116 0.121000 13.521763 23.526915 0.000000 240.723619 0.000000 1989.430553 -EDGE_SE2 496 497 0.639602 -0.025661 -0.083377 11.547127 -10.068553 0.000000 243.615831 0.000000 2130.005800 -EDGE_SE2 497 498 0.634982 -0.033636 -0.099467 11.622457 -10.978306 0.000000 246.809304 0.000000 2068.119413 -EDGE_SE2 498 499 0.638794 -0.029903 -0.015370 11.341287 7.326250 0.000000 244.297416 0.000000 2424.886152 -EDGE_SE2 499 500 0.581639 0.165523 0.331283 11.876261 14.147113 0.000000 272.681816 0.000000 1410.584918 -EDGE_SE2 500 501 0.608658 -0.019295 -0.065817 11.412115 -8.816677 0.000000 269.359185 0.000000 2200.770331 -EDGE_SE2 501 502 0.717458 -0.037860 -0.078159 11.229253 -4.643405 0.000000 193.613030 0.000000 2150.673003 -EDGE_SE2 502 503 0.468033 -0.006282 -0.011528 11.112706 0.842757 0.000000 456.422908 0.000000 2443.341609 -EDGE_SE2 503 504 0.001010 -0.000329 0.882265 76783402.732445 30131648.184749 0.000000 11824394.003794 0.000000 705.632337 -EDGE_SE2 504 505 0.222895 0.156032 0.638914 12.174041 37.721370 0.000000 1349.770700 0.000000 930.738499 -EDGE_SE2 505 506 0.625769 -0.021473 -0.145256 14.102191 -26.846905 0.000000 252.079673 0.000000 1906.052494 -EDGE_SE2 506 507 0.635814 -0.018204 -0.072178 11.558631 -10.268279 0.000000 246.715411 0.000000 2174.734405 -EDGE_SE2 507 508 0.638204 -0.013687 -0.007658 11.155629 3.229265 0.000000 245.359315 0.000000 2462.145389 -EDGE_SE2 508 509 0.642039 -0.008726 -0.051671 11.446573 -8.804866 0.000000 242.212186 0.000000 2260.373525 -EDGE_SE2 509 510 0.372102 -0.006043 -0.009950 11.139237 4.471542 0.000000 722.013535 0.000000 2450.982789 -EDGE_SE2 510 511 0.002084 -0.003553 0.891003 5160201.305808 -1945038.253710 0.000000 733157.306436 0.000000 699.126192 -EDGE_SE2 511 512 0.007335 0.005942 1.221397 297144.725264 495141.758266 0.000000 825112.510283 0.000000 506.626201 -EDGE_SE2 512 513 -0.002181 -0.000566 0.972737 8538321.615481 9762487.124922 0.000000 11162190.656524 0.000000 642.394025 -EDGE_SE2 513 514 0.090094 0.023767 0.232272 18.681434 -295.052416 0.000000 11510.742828 0.000000 1646.367741 -EDGE_SE2 514 515 0.658710 0.013018 0.004928 11.159348 -3.251856 0.000000 230.330528 0.000000 2475.540949 -EDGE_SE2 515 516 0.637378 -0.008635 0.019744 11.371458 7.817478 0.000000 245.848124 0.000000 2404.128580 -EDGE_SE2 516 517 0.633811 0.029113 0.032052 11.156620 -3.285893 0.000000 248.362090 0.000000 2347.128404 -EDGE_SE2 517 518 0.634675 0.007993 0.028090 11.168044 3.673667 0.000000 248.158131 0.000000 2365.253746 -EDGE_SE2 518 519 0.560153 0.002654 -0.012150 11.198833 -5.193662 0.000000 318.608437 0.000000 2440.339501 -EDGE_SE2 519 520 0.197101 -0.000544 0.405434 414.955475 933.778631 0.000000 2170.216473 0.000000 1265.665952 -EDGE_SE2 520 521 0.006002 0.005024 1.019492 163989.160959 490677.362406 0.000000 1468282.469392 0.000000 612.993310 -EDGE_SE2 521 522 0.414779 0.108184 0.270025 11.229248 7.935203 0.000000 544.113259 0.000000 1549.942078 -EDGE_SE2 522 523 0.644866 -0.002177 -0.013262 11.133525 -2.267210 0.000000 240.444921 0.000000 2434.986160 -EDGE_SE2 523 524 0.606582 -0.016880 -0.047652 11.213538 -5.164087 0.000000 271.469885 0.000000 2277.749269 -EDGE_SE2 524 525 0.576823 0.002529 0.018772 11.171018 4.163585 0.000000 300.483332 0.000000 2408.718278 -EDGE_SE2 525 526 0.607148 -0.019364 -0.063586 11.372241 -8.233863 0.000000 270.738644 0.000000 2210.012777 -EDGE_SE2 526 527 0.632532 -0.013902 -0.038859 11.179151 -4.029527 0.000000 249.750981 0.000000 2316.470615 -EDGE_SE2 527 528 0.639965 -0.031254 -0.079842 11.335080 -7.212289 0.000000 243.362638 0.000000 2143.974316 -EDGE_SE2 528 529 0.630138 0.005118 -0.025519 11.383434 -8.091842 0.000000 251.553301 0.000000 2377.128104 -EDGE_SE2 529 530 0.643013 -0.010371 -0.027118 11.138973 -2.535041 0.000000 241.767362 0.000000 2369.732519 -EDGE_SE2 530 531 0.632204 -0.021106 -0.076364 11.552220 -10.254093 0.000000 249.479589 0.000000 2157.852130 -EDGE_SE2 531 532 0.210203 0.000529 0.053978 17.069737 115.687987 0.000000 2257.218094 0.000000 2250.489117 -EDGE_SE2 532 533 0.010481 0.007945 1.006775 71059.615350 189815.528908 0.000000 507128.543079 0.000000 620.787044 -EDGE_SE2 533 534 0.004524 0.002070 0.671821 233294.669406 942460.043629 0.000000 3807527.338703 0.000000 894.459037 -EDGE_SE2 534 535 0.000000 0.000000 0.001338 11.111807 0.520333 0.000000 399.999304 0.000000 2493.323403 -EDGE_SE2 535 536 0.357295 0.039869 0.132965 11.474755 16.648687 0.000000 773.337063 0.000000 1947.632537 -EDGE_SE2 536 537 0.617574 -0.018145 -0.055950 11.288271 -6.664110 0.000000 261.790435 0.000000 2242.091332 -EDGE_SE2 537 538 0.579730 -0.014385 -0.025102 11.111136 -0.083914 0.000000 297.359512 0.000000 2379.062475 -EDGE_SE2 538 539 0.638569 -0.022758 -0.062503 11.280003 -6.281777 0.000000 244.755892 0.000000 2214.520366 -EDGE_SE2 539 540 0.636808 -0.030043 -0.090399 11.550435 -10.149862 0.000000 245.607132 0.000000 2102.660323 -EDGE_SE2 540 541 0.624998 0.051843 0.165279 12.763015 19.972919 0.000000 252.600591 0.000000 1841.111831 -EDGE_SE2 541 542 0.637879 0.044546 0.058251 11.141827 -2.677719 0.000000 244.543713 0.000000 2232.351783 -EDGE_SE2 542 543 0.119005 -0.001027 -0.027249 13.554992 -131.231977 0.000000 7058.031360 0.000000 2369.128157 -EDGE_SE2 543 544 0.004143 0.001613 0.643358 365523.202414 1309813.828807 0.000000 4693733.444673 0.000000 925.711464 -EDGE_SE2 544 545 0.011964 0.010101 1.076679 54873.490374 139170.850294 0.000000 353049.492454 0.000000 579.697285 -EDGE_SE2 545 546 -0.062408 -0.034041 0.835070 2157.534535 6151.646423 0.000000 17641.720853 0.000000 742.394487 -EDGE_SE2 546 547 0.004683 0.006620 1.031598 8884.576322 115819.915331 0.000000 1511737.642851 0.000000 605.709415 -EDGE_SE2 547 548 0.010894 0.005062 0.931876 157491.371124 290395.414023 0.000000 535503.600637 0.000000 669.856096 -EDGE_SE2 548 549 0.018521 0.007174 0.814504 46970.071545 98477.220300 0.000000 206526.818200 0.000000 759.318793 -EDGE_SE2 549 550 0.007039 -0.001728 -0.474679 102346.133104 -429334.075047 0.000000 1801229.739954 0.000000 1149.595399 -EDGE_SE2 550 551 0.012919 -0.003649 -0.620137 63414.169645 -176527.986637 0.000000 491503.647693 0.000000 952.437591 -EDGE_SE2 551 552 0.004870 -0.001510 -0.626201 393240.954950 -1165183.372361 0.000000 3452577.879626 0.000000 945.347676 -EDGE_SE2 552 553 0.131013 -0.071366 -0.571551 34.798953 -324.963500 0.000000 4469.148228 0.000000 1012.238963 -EDGE_SE2 553 554 0.656516 -0.001289 -0.033128 11.325592 -6.879883 0.000000 231.796023 0.000000 2342.241894 -EDGE_SE2 554 555 0.640736 0.024110 0.091367 11.781224 12.453936 0.000000 242.565349 0.000000 2098.932021 -EDGE_SE2 555 556 0.644807 0.029102 0.137696 13.068095 21.074909 0.000000 238.068451 0.000000 1931.468129 -EDGE_SE2 556 557 0.641564 -0.010754 -0.042948 11.270029 -6.066916 0.000000 242.724912 0.000000 2298.342233 -EDGE_SE2 557 558 0.615263 0.021826 0.078921 11.588181 10.969921 0.000000 263.357654 0.000000 2147.636202 -EDGE_SE2 558 559 0.005363 -0.000612 -0.410558 293857.680729 -960260.813810 0.000000 3138046.146667 0.000000 1256.487325 -EDGE_SE2 559 560 0.000000 0.000000 -0.505043 102.152456 -164.670704 0.000000 308.958656 0.000000 1103.677058 -EDGE_SE2 560 561 0.009398 0.003440 0.501104 22371.403618 147733.503165 0.000000 976080.093687 0.000000 1109.476905 -EDGE_SE2 561 562 0.177331 0.126693 0.638384 11.791812 37.750509 0.000000 2104.689083 0.000000 931.340765 -EDGE_SE2 562 563 0.597201 -0.094603 -0.194811 11.484023 -9.885231 0.000000 273.150922 0.000000 1751.223531 -EDGE_SE2 563 564 0.639558 0.013847 0.046248 11.252240 5.735744 0.000000 244.222662 0.000000 2283.866567 -EDGE_SE2 564 565 0.614599 -0.011365 -0.051966 11.395132 -8.481100 0.000000 264.363876 0.000000 2259.105962 -EDGE_SE2 565 566 0.005382 -0.000625 0.804171 2155482.804415 1641813.690713 0.000000 1250573.669361 0.000000 768.041369 -EDGE_SE2 566 567 -0.001231 0.000678 0.856086 48423129.554559 10395439.301461 0.000000 2231696.342135 0.000000 725.677769 -EDGE_SE2 567 568 0.583042 0.017568 0.046196 11.184172 4.544849 0.000000 293.831241 0.000000 2284.093607 -EDGE_SE2 568 569 0.628101 -0.010139 -0.052147 11.425095 -8.716657 0.000000 253.098625 0.000000 2258.328765 -EDGE_SE2 569 570 0.639821 -0.001979 -0.004808 11.111796 -0.399705 0.000000 244.274090 0.000000 2476.132272 -EDGE_SE2 570 571 0.348563 -0.003118 -0.043397 12.074353 -27.948587 0.000000 822.042846 0.000000 2296.364589 -EDGE_SE2 571 572 0.037203 -0.034953 -0.237353 9379.952208 16482.424026 0.000000 29008.326343 0.000000 1632.874389 -EDGE_SE2 572 573 0.082599 0.001138 0.282645 1044.389047 3750.080318 0.000000 13621.294688 0.000000 1519.592228 -EDGE_SE2 573 574 0.006029 0.005935 0.955816 43915.035779 243749.664142 0.000000 1353281.899972 0.000000 653.557826 -EDGE_SE2 574 575 0.017352 0.009648 1.009306 58713.654313 106982.648688 0.000000 194982.001569 0.000000 619.224094 -EDGE_SE2 575 576 -0.000693 0.000729 1.024139 92116121.130465 -24932672.587732 0.000000 6748430.711509 0.000000 610.181931 -EDGE_SE2 576 577 0.005808 0.005602 0.968758 61460.098525 300963.429168 0.000000 1474062.832839 0.000000 644.993297 -EDGE_SE2 577 578 0.020578 -0.005874 -0.365770 1686.236926 -19051.115635 0.000000 216678.422748 0.000000 1340.246481 -EDGE_SE2 578 579 0.649778 -0.007064 0.014101 11.251830 5.633981 0.000000 236.679123 0.000000 2430.958734 -EDGE_SE2 579 580 0.646533 0.021127 0.074055 11.501231 9.420338 0.000000 238.586536 0.000000 2167.139990 -EDGE_SE2 580 581 0.641277 0.007721 0.041304 11.309760 6.786133 0.000000 242.935131 0.000000 2305.605160 -EDGE_SE2 581 582 0.642222 0.008953 0.042003 11.293216 6.487457 0.000000 242.225126 0.000000 2302.512889 -EDGE_SE2 582 583 0.324533 0.007424 0.078126 13.971366 51.714099 0.000000 946.114403 0.000000 2150.804664 -EDGE_SE2 583 584 0.003585 0.000066 0.840201 4172109.666193 3878928.313892 0.000000 3606370.037121 0.000000 738.260001 -EDGE_SE2 584 585 0.609333 0.022255 0.117010 12.778611 20.669000 0.000000 267.307574 0.000000 2003.668573 -EDGE_SE2 585 586 0.610182 0.017652 0.096276 12.276387 17.274488 0.000000 267.194725 0.000000 2080.176547 -EDGE_SE2 586 587 0.632351 0.024309 0.024257 11.158994 -3.379740 0.000000 249.665755 0.000000 2382.989492 -EDGE_SE2 587 588 0.643770 -0.006740 0.003322 11.154886 3.173805 0.000000 241.219104 0.000000 2483.472403 -EDGE_SE2 588 589 0.633840 0.040950 0.080270 11.169866 3.729294 0.000000 247.815430 0.000000 2142.275779 -EDGE_SE2 589 590 0.644706 0.014870 0.073779 11.700561 11.612184 0.000000 239.871719 0.000000 2168.254200 -EDGE_SE2 590 591 0.632424 0.012303 0.002621 11.178752 -4.018640 0.000000 249.862554 0.000000 2486.946343 -EDGE_SE2 591 592 0.642169 0.006914 0.001997 11.128903 -2.028750 0.000000 242.448415 0.000000 2490.044831 -EDGE_SE2 592 593 0.271993 0.001273 0.212505 68.183858 270.652782 0.000000 1294.612122 0.000000 1700.485497 -EDGE_SE2 593 594 0.014453 0.008841 0.993097 64316.365031 135154.721370 0.000000 284074.972077 0.000000 629.336815 -EDGE_SE2 594 595 0.571176 0.080832 0.240324 13.980407 28.672593 0.000000 297.633480 0.000000 1625.061173 -EDGE_SE2 595 596 0.575835 0.004878 -0.017875 11.312665 -7.648565 0.000000 301.358130 0.000000 2412.965503 -EDGE_SE2 596 597 0.635351 -0.013108 -0.034135 11.154253 -3.193993 0.000000 247.578146 0.000000 2337.682549 -EDGE_SE2 597 598 0.604127 -0.006451 -0.039602 11.330957 -7.598611 0.000000 273.744081 0.000000 2313.160651 -EDGE_SE2 598 599 0.385673 -0.010715 -0.063459 11.952011 -23.555254 0.000000 670.939617 0.000000 2210.540655 -EDGE_SE2 599 600 0.008688 0.002526 0.814757 314076.796383 533827.575685 0.000000 907375.060518 0.000000 759.107091 -EDGE_SE2 600 601 0.021686 0.011399 1.028615 44738.476040 73830.093373 0.000000 121880.188267 0.000000 607.492253 -EDGE_SE2 601 602 0.018101 0.007667 1.024411 88285.368598 122674.329555 0.000000 170491.062574 0.000000 610.017974 -EDGE_SE2 602 603 0.186319 0.162792 0.780432 17.405089 100.856712 0.000000 1627.271409 0.000000 788.658931 -EDGE_SE2 603 604 0.621077 -0.063008 -0.240492 15.850028 -33.777361 0.000000 251.864479 0.000000 1624.621039 -EDGE_SE2 604 605 0.633484 0.018906 0.082620 11.773196 12.531662 0.000000 248.305264 0.000000 2132.985568 -EDGE_SE2 605 606 0.635159 0.014918 0.042086 11.193000 4.401211 0.000000 247.658010 0.000000 2302.146123 -EDGE_SE2 606 607 0.573078 -0.057501 -0.081034 11.215573 5.506259 0.000000 301.350193 0.000000 2139.248825 -EDGE_SE2 607 608 0.372357 0.012526 0.044458 11.194332 7.682633 0.000000 720.342546 0.000000 2291.701491 -EDGE_SE2 608 609 0.009981 0.001237 0.336295 44194.195786 204270.386082 0.000000 944408.518792 0.000000 1400.022844 -EDGE_SE2 609 610 0.008024 0.008992 0.932617 5618.242041 61880.517104 0.000000 682926.927594 0.000000 669.342525 -EDGE_SE2 610 611 0.619179 0.006175 0.002964 11.123375 -1.749910 0.000000 260.797662 0.000000 2485.245630 -EDGE_SE2 611 612 0.495865 -0.011645 0.002777 11.383631 10.376429 0.000000 406.201910 0.000000 2486.172625 -EDGE_SE2 612 613 -0.032580 0.001507 0.463705 22407.672171 40045.920128 0.000000 71614.770023 0.000000 1166.898001 -EDGE_SE2 613 614 0.006074 0.002811 1.037837 720992.332387 1043867.597380 0.000000 1511367.480327 0.000000 602.006419 -EDGE_SE2 614 615 0.468918 0.167392 0.304515 11.688040 -15.032631 0.000000 402.805589 0.000000 1469.067849 -EDGE_SE2 615 616 0.634148 0.014484 -0.051156 12.408628 -17.503753 0.000000 247.240026 0.000000 2262.588948 -EDGE_SE2 616 617 0.620915 -0.099361 -0.217030 11.933466 -14.077035 0.000000 252.081317 0.000000 1687.863964 -EDGE_SE2 617 618 0.637519 0.006833 0.010118 11.111196 -0.140914 0.000000 246.016254 0.000000 2450.167576 -EDGE_SE2 618 619 0.602001 -0.001093 -0.001468 11.111143 0.091989 0.000000 275.933653 0.000000 2492.676131 -EDGE_SE2 619 620 0.611116 -0.021079 -0.096329 12.090448 -15.813910 0.000000 266.467179 0.000000 2079.975428 -EDGE_SE2 620 621 -0.351742 0.001000 -0.051606 13.005075 -38.809484 0.000000 806.361703 0.000000 2260.652962 -EDGE_SE2 621 622 -0.288473 0.005647 -0.075042 14.769187 -65.879798 0.000000 1197.567688 0.000000 2163.162499 -EDGE_SE2 622 623 -0.003587 0.000519 -0.537149 1119299.663768 -2695881.271885 0.000000 6493221.297933 0.000000 1058.054588 -EDGE_SE2 623 624 -0.002684 0.001648 -0.642690 84963.761375 -921398.117942 0.000000 9993513.245668 0.000000 926.464498 -EDGE_SE2 624 625 0.007502 -0.002176 -0.658633 221323.684950 -560152.893180 0.000000 1417785.340096 0.000000 908.739498 -EDGE_SE2 625 626 0.007582 -0.000720 -0.618128 430777.189603 -746427.081854 0.000000 1293412.370737 0.000000 954.803710 -EDGE_SE2 626 627 0.339972 -0.139061 -0.410806 11.481721 -16.444927 0.000000 740.815480 0.000000 1256.045618 -EDGE_SE2 627 628 0.641810 -0.041240 -0.100917 11.422475 -8.468830 0.000000 241.456222 0.000000 2062.675227 -EDGE_SE2 628 629 0.640763 0.030371 0.071050 11.241212 5.491249 0.000000 242.883687 0.000000 2179.317557 -EDGE_SE2 629 630 0.608678 0.024217 0.085089 11.641507 11.694459 0.000000 268.956806 0.000000 2123.289866 -EDGE_SE2 630 631 0.520687 0.012252 0.020220 11.115021 -1.182335 0.000000 368.639644 0.000000 2401.885734 -EDGE_SE2 631 632 0.003617 -0.000095 0.676209 3189142.029325 3767706.315238 0.000000 4451258.564395 0.000000 889.781790 -EDGE_SE2 632 633 0.052581 0.076324 1.075605 146.388666 1246.996416 0.000000 11505.997044 0.000000 580.297357 -EDGE_SE2 633 634 0.651291 -0.000853 0.025227 11.269271 5.958489 0.000000 235.590568 0.000000 2378.482380 -EDGE_SE2 634 635 0.638650 -0.043082 -0.137291 12.248607 -16.238485 0.000000 242.925867 0.000000 1932.844002 -EDGE_SE2 635 636 0.635527 0.004328 -0.019084 11.269630 -6.120407 0.000000 247.419146 0.000000 2407.243610 -EDGE_SE2 636 637 0.632517 -0.030952 -0.100684 11.749524 -12.316243 0.000000 248.715635 0.000000 2063.548601 -EDGE_SE2 637 638 0.419086 -0.009115 -0.030747 11.156304 -5.021448 0.000000 569.055296 0.000000 2353.075434 -EDGE_SE2 638 639 0.640680 0.028288 0.078765 11.389438 8.031492 0.000000 242.870396 0.000000 2148.257386 -EDGE_SE2 639 640 0.645185 -0.028949 -0.069702 11.252424 -5.682397 0.000000 239.608542 0.000000 2184.813613 -EDGE_SE2 640 641 0.631149 0.010125 -0.010170 11.275857 -6.284012 0.000000 250.806675 0.000000 2449.915330 -EDGE_SE2 641 642 0.608456 -0.016443 -0.047551 11.220217 -5.312718 0.000000 269.804578 0.000000 2278.188510 -EDGE_SE2 642 643 0.501922 -0.014902 -0.065028 11.592531 -13.614212 0.000000 396.111379 0.000000 2204.032313 -EDGE_SE2 643 644 0.006192 0.003634 0.763605 103362.922493 435664.745636 0.000000 1836493.394795 0.000000 803.780315 -EDGE_SE2 644 645 0.147583 0.161030 0.956903 45.062660 263.875747 0.000000 2061.986889 0.000000 652.831965 -EDGE_SE2 645 646 0.624864 0.078137 0.297396 18.253618 40.874666 0.000000 245.025960 0.000000 1485.234058 -EDGE_SE2 646 647 0.626416 0.074352 0.291155 18.229469 40.732090 0.000000 244.184966 0.000000 1499.626982 -EDGE_SE2 647 648 0.630437 0.066336 0.168411 12.070691 15.073373 0.000000 247.888334 0.000000 1831.254626 -EDGE_SE2 648 649 0.592663 -0.072497 -0.334526 23.127883 -55.612924 0.000000 268.484510 0.000000 1403.737590 -EDGE_SE2 649 650 0.621511 -0.143009 -0.254374 11.297892 -6.619122 0.000000 245.678334 0.000000 1588.861060 -EDGE_SE2 650 651 0.144853 0.010732 0.805829 2122.876396 2350.861156 0.000000 2628.138776 0.000000 766.631681 -EDGE_SE2 651 652 0.002718 0.001656 1.033599 2156297.352241 4079208.548390 0.000000 7716956.136248 0.000000 604.518184 -EDGE_SE2 652 653 0.014957 0.011986 1.038848 34378.938116 90407.858801 0.000000 237837.637992 0.000000 601.409535 -EDGE_SE2 653 654 0.267736 0.151078 0.517447 11.125502 3.881714 0.000000 1058.107188 0.000000 1085.707770 -EDGE_SE2 654 655 0.563434 -0.005218 -0.003312 11.121867 1.807836 0.000000 314.964252 0.000000 2483.521908 -EDGE_SE2 655 656 0.610635 -0.014726 -0.011084 11.154711 3.346600 0.000000 267.986619 0.000000 2445.487982 -EDGE_SE2 656 657 0.631799 0.103933 0.278849 14.219359 26.720114 0.000000 240.811095 0.000000 1528.626076 -EDGE_SE2 657 658 0.640227 0.007103 -0.006984 11.187191 -4.208049 0.000000 243.861599 0.000000 2465.442445 -EDGE_SE2 658 659 0.497774 -0.026439 -0.071049 11.237681 -7.036752 0.000000 402.323496 0.000000 2179.321626 -EDGE_SE2 659 660 0.006409 -0.000096 0.600351 810833.659716 1147194.412851 0.000000 1623122.139710 0.000000 976.134174 -EDGE_SE2 660 661 0.169432 0.128488 0.653648 11.162367 10.620021 0.000000 2211.525163 0.000000 914.226633 -EDGE_SE2 661 662 0.629749 0.003998 0.069631 12.075080 15.212434 0.000000 251.179162 0.000000 2185.103670 -EDGE_SE2 662 663 0.621897 0.037784 0.101008 11.511766 9.929781 0.000000 257.209513 0.000000 2062.334274 -EDGE_SE2 663 664 0.007280 -0.002392 0.538314 970988.716591 843174.347297 0.000000 732204.084386 0.000000 1056.452618 -EDGE_SE2 664 665 0.026579 0.029587 0.878851 111.857316 2521.446990 0.000000 63117.159733 0.000000 708.199031 -EDGE_SE2 665 666 0.623804 0.018831 0.034452 11.115596 1.049644 0.000000 256.744183 0.000000 2336.250038 -EDGE_SE2 666 667 0.580478 0.005759 0.002114 11.128518 -2.229713 0.000000 296.729354 0.000000 2489.463423 -EDGE_SE2 667 668 0.608507 -0.000467 0.023179 11.259577 6.198692 0.000000 269.917040 0.000000 2388.013473 -EDGE_SE2 668 669 0.638606 0.001692 -0.027742 11.327262 -7.110068 0.000000 244.989751 0.000000 2366.855797 -EDGE_SE2 669 670 0.636315 -0.034673 -0.062258 11.125493 -1.838895 0.000000 246.230714 0.000000 2215.542002 -EDGE_SE2 670 671 0.308072 0.001150 0.052261 13.564460 50.513802 0.000000 1051.177078 0.000000 2257.839465 -EDGE_SE2 671 672 -0.576602 0.036531 -0.092061 11.350145 -8.300360 0.000000 299.337680 0.000000 2096.265145 -EDGE_SE2 672 673 -0.262392 0.011580 -0.133741 22.638322 -128.254010 0.000000 1438.090461 0.000000 1944.967298 -EDGE_SE2 673 674 -0.005814 0.002674 -0.655099 120542.083833 -528941.427411 0.000000 2321232.182459 0.000000 912.624358 -EDGE_SE2 674 675 -0.014637 0.005942 -0.615221 20765.078980 -88798.929746 0.000000 379950.502646 0.000000 958.243990 -EDGE_SE2 675 676 -0.006630 0.003741 -0.630060 23265.609241 -198963.775781 0.000000 1702330.544222 0.000000 940.876947 -EDGE_SE2 676 677 -0.012856 0.004015 -0.622499 54491.338930 -164518.778220 0.000000 496823.064188 0.000000 949.666532 -EDGE_SE2 677 678 0.191689 -0.090627 -0.451238 11.315076 -21.245540 0.000000 2224.105339 0.000000 1187.032313 -EDGE_SE2 678 679 0.570835 0.011396 0.059784 11.579724 11.761290 0.000000 306.296841 0.000000 2225.898166 -EDGE_SE2 679 680 0.434701 0.056384 0.340338 33.525701 104.470312 0.000000 498.028172 0.000000 1391.589518 -EDGE_SE2 680 681 0.616588 -0.017915 -0.025786 11.113788 0.820773 0.000000 262.808564 0.000000 2375.890788 -EDGE_SE2 681 682 0.634780 0.014947 0.049632 11.272332 6.178273 0.000000 247.873967 0.000000 2269.163993 -EDGE_SE2 682 683 0.300050 0.004977 0.161644 34.081549 157.239703 0.000000 1087.465169 0.000000 1852.652221 -EDGE_SE2 683 684 0.008066 0.002610 1.069340 655223.236656 694424.027218 0.000000 735993.720066 0.000000 583.816417 -EDGE_SE2 684 685 0.408559 0.177472 0.439476 11.545242 14.621378 0.000000 503.554260 0.000000 1206.510628 -EDGE_SE2 685 686 0.481253 -0.056338 -0.146676 11.487851 -12.495538 0.000000 425.557060 0.000000 1901.334651 -EDGE_SE2 686 687 0.633778 -0.013418 -0.036773 11.168993 -3.709053 0.000000 248.788111 0.000000 2325.801528 -EDGE_SE2 687 688 0.633546 -0.023306 -0.013253 11.242546 5.587827 0.000000 248.672293 0.000000 2435.029417 -EDGE_SE2 688 689 0.601923 0.011148 0.026350 11.127352 2.073709 0.000000 275.894586 0.000000 2373.280306 -EDGE_SE2 689 690 0.577060 0.031776 0.072952 11.203899 5.171117 0.000000 299.300801 0.000000 2171.597942 -EDGE_SE2 690 691 0.431081 -0.000968 -0.029004 11.488376 -14.095403 0.000000 537.744126 0.000000 2361.053797 -EDGE_SE2 691 692 -0.008991 -0.001137 0.532009 190083.391915 441924.473409 0.000000 1027500.439761 0.000000 1065.166196 -EDGE_SE2 692 693 -0.002490 -0.004336 1.036147 719.063258 -53205.166853 0.000000 3998572.017505 0.000000 603.006163 -EDGE_SE2 693 694 -0.004998 -0.000127 0.832038 2085335.472274 1998610.421428 0.000000 1915513.414270 0.000000 744.853827 -EDGE_SE2 694 695 0.001511 0.001312 0.796919 166502.359918 2031923.976353 0.000000 24798401.868961 0.000000 774.253197 -EDGE_SE2 695 696 0.013256 0.002978 1.021557 279104.028874 270742.205141 0.000000 262652.464508 0.000000 611.741616 -EDGE_SE2 696 697 0.014932 -0.001676 -0.254525 8971.193925 -62353.454280 0.000000 433930.455572 0.000000 1588.478599 -EDGE_SE2 697 698 0.334592 -0.212289 -0.657753 16.435194 -57.473689 0.000000 631.541865 0.000000 909.704543 -EDGE_SE2 698 699 0.645635 0.022320 0.112426 12.493854 17.721303 0.000000 238.228242 0.000000 2020.215724 -EDGE_SE2 699 700 0.637453 0.017479 0.051850 11.251293 5.735412 0.000000 245.770774 0.000000 2259.604267 -EDGE_SE2 700 701 0.580454 0.032375 0.057254 11.111784 0.437751 0.000000 295.879739 0.000000 2236.564024 -EDGE_SE2 701 702 0.576635 -0.068380 -0.117543 11.111180 0.139782 0.000000 296.573785 0.000000 2001.757773 -EDGE_SE2 702 703 0.620013 -0.001990 0.031996 11.419637 8.759800 0.000000 259.823358 0.000000 2347.383139 -EDGE_SE2 703 704 0.636789 0.025712 0.015764 11.253257 -5.779092 0.000000 246.065659 0.000000 2423.005361 -EDGE_SE2 704 705 0.643209 0.030107 0.064485 11.183283 4.074239 0.000000 241.110228 0.000000 2206.281466 -EDGE_SE2 705 706 0.514363 -0.039200 -0.277636 25.728836 -71.533878 0.000000 361.172137 0.000000 1531.530774 -EDGE_SE2 706 707 0.003881 -0.001622 -0.533536 106334.972814 -767757.982233 0.000000 5543943.675681 0.000000 1063.046000 -EDGE_SE2 707 708 -0.003691 0.001823 -0.654541 223240.622476 -1125745.646018 0.000000 5677142.471470 0.000000 913.240034 -EDGE_SE2 708 709 -0.067573 0.007248 -0.341732 1183.126036 -4897.853094 0.000000 20479.250565 0.000000 1388.700057 -EDGE_SE2 709 710 -0.014148 0.002189 -0.575257 81786.222098 -182245.919313 0.000000 406168.616806 0.000000 1007.481714 -EDGE_SE2 710 711 0.000644 0.000757 -0.611741 100340028.914478 -9326915.500645 0.000000 866976.800978 0.000000 962.386453 -EDGE_SE2 711 712 -0.004894 0.001455 -0.574644 304805.524713 -1037473.284048 0.000000 3531410.530133 0.000000 1008.266280 -EDGE_SE2 712 713 0.477793 -0.132293 -0.294292 11.342379 -9.563968 0.000000 406.624099 0.000000 1492.366443 -EDGE_SE2 713 714 0.567602 -0.077796 -0.205164 12.504613 -20.177539 0.000000 303.276539 0.000000 1721.264882 -EDGE_SE2 714 715 0.633486 0.028573 0.105231 11.969833 14.257268 0.000000 247.822982 0.000000 2046.604352 -EDGE_SE2 715 716 0.639776 -0.022007 -0.136206 13.517556 -23.552031 0.000000 241.616372 0.000000 1936.537236 -EDGE_SE2 716 717 0.632432 0.018685 0.086524 11.885459 13.573115 0.000000 249.026579 0.000000 2117.685003 -EDGE_SE2 717 718 0.776383 -0.078919 -0.173172 11.900522 -10.964942 0.000000 163.414455 0.000000 1816.421486 -EDGE_SE2 718 719 0.636837 0.028128 0.076417 11.355832 7.579234 0.000000 245.847108 0.000000 2157.639641 -EDGE_SE2 719 720 0.632529 -0.017060 -0.057232 11.329664 -7.218698 0.000000 249.541537 0.000000 2236.657107 -EDGE_SE2 720 721 0.638105 0.018029 0.070335 11.525887 9.849065 0.000000 244.982458 0.000000 2182.230164 -EDGE_SE2 721 722 0.025289 0.000135 0.068811 640.196727 9897.678857 0.000000 155735.617178 0.000000 2188.457812 -EDGE_SE2 722 723 0.006445 0.007867 1.098357 43580.586864 200575.333708 0.000000 923374.631033 0.000000 567.781519 -EDGE_SE2 723 724 0.010463 0.006590 1.077175 158723.565692 280363.009735 0.000000 495267.878673 0.000000 579.420471 -EDGE_SE2 724 725 0.010678 0.005468 0.639413 19006.567647 113303.006550 0.000000 675834.367551 0.000000 930.171994 -EDGE_SE2 725 726 0.290588 0.137540 0.458060 11.355500 15.286330 0.000000 967.259181 0.000000 1175.950976 -EDGE_SE2 726 727 0.635716 0.023142 0.032574 11.114541 -0.899732 0.000000 247.111115 0.000000 2344.755903 -EDGE_SE2 727 728 0.637440 -0.010740 0.003027 11.203891 4.667737 0.000000 245.942991 0.000000 2484.933444 -EDGE_SE2 728 729 0.638658 0.024646 0.059374 11.212224 4.859951 0.000000 244.701967 0.000000 2227.621438 -EDGE_SE2 729 730 0.629725 0.021040 0.039078 11.118875 1.367234 0.000000 251.883563 0.000000 2315.494262 -EDGE_SE2 730 731 0.635128 0.000033 0.013336 11.152896 3.145232 0.000000 247.858605 0.000000 2434.630538 -EDGE_SE2 731 732 0.123756 0.004174 0.448902 1070.432039 2403.087812 0.000000 5462.557297 0.000000 1190.863501 -EDGE_SE2 732 733 0.000083 0.001424 1.000990 11773189.473890 -20977730.743166 0.000000 37378633.397513 0.000000 624.381709 -EDGE_SE2 733 734 0.552572 0.038413 0.079326 11.142093 3.122929 0.000000 325.902343 0.000000 2146.024772 -EDGE_SE2 734 735 0.600091 -0.007820 -0.030980 11.196982 -4.783337 0.000000 277.560623 0.000000 2352.011970 -EDGE_SE2 735 736 0.005111 -0.000077 0.602090 1281626.650843 1806077.209424 0.000000 2545169.768506 0.000000 974.015847 -EDGE_SE2 736 737 0.008677 0.008287 0.804006 1211.768495 28855.042050 0.000000 693475.760746 0.000000 768.181871 -EDGE_SE2 737 738 0.598858 0.011099 0.020076 11.111750 0.413426 0.000000 278.741652 0.000000 2402.563911 -EDGE_SE2 738 739 0.625793 -0.054407 -0.056575 11.331296 7.301220 0.000000 253.215672 0.000000 2239.439570 -EDGE_SE2 739 740 0.522300 0.024647 0.064307 11.215445 6.082008 0.000000 365.653135 0.000000 2207.019506 -EDGE_SE2 740 741 -0.000981 -0.000074 -0.367127 18919361.341981 -39981559.645604 0.000000 84491555.069462 0.000000 1337.587765 -EDGE_SE2 741 742 0.011219 -0.001990 -0.650273 160936.661861 -313150.446277 0.000000 609381.105788 0.000000 917.969856 -EDGE_SE2 742 743 0.004918 -0.001325 -0.614408 456134.364729 -1245052.232453 0.000000 3398555.362562 0.000000 959.208992 -EDGE_SE2 743 744 0.009459 -0.002723 -0.537185 66620.250624 -253582.580605 0.000000 965406.035238 0.000000 1058.005031 -EDGE_SE2 744 745 0.002047 -0.000908 -0.591149 593780.161881 -3389363.396311 0.000000 19347237.473549 0.000000 987.457262 -EDGE_SE2 745 746 0.494445 -0.175533 -0.472825 17.183290 -45.841209 0.000000 357.183969 0.000000 1152.491455 -EDGE_SE2 746 747 0.638469 -0.005433 -0.034207 11.265722 -6.015279 0.000000 245.140841 0.000000 2337.357068 -EDGE_SE2 747 748 0.577733 -0.023010 -0.067174 11.326766 -7.878192 0.000000 298.912675 0.000000 2195.176966 -EDGE_SE2 748 749 0.069701 0.001911 0.431306 3186.109937 7428.826456 0.000000 17392.995499 0.000000 1220.323642 -EDGE_SE2 749 750 0.003545 0.004632 0.930924 530.021459 39050.161440 0.000000 2938698.139852 0.000000 670.516775 -EDGE_SE2 750 751 0.221430 0.155717 0.642978 12.335877 40.697289 0.000000 1363.426091 0.000000 926.139724 -EDGE_SE2 751 752 0.622533 -0.037077 -0.102200 11.559653 -10.494975 0.000000 256.672582 0.000000 2057.875967 -EDGE_SE2 752 753 0.636978 0.006588 0.064190 11.792803 12.647310 0.000000 245.754530 0.000000 2207.504825 -EDGE_SE2 753 754 0.633682 -0.063409 -0.161022 11.994454 -14.394628 0.000000 245.680720 0.000000 1854.637814 -EDGE_SE2 754 755 0.634065 0.020125 0.076284 11.582011 10.562020 0.000000 248.011279 0.000000 2158.172928 -EDGE_SE2 755 756 0.630931 -0.052093 -0.191444 13.935694 -25.795248 0.000000 246.683906 0.000000 1761.135371 -EDGE_SE2 756 757 0.634731 0.023338 0.098895 12.024248 14.675298 0.000000 246.962348 0.000000 2070.272980 -EDGE_SE2 757 758 0.593380 0.045763 0.126480 11.775379 13.406035 0.000000 281.667065 0.000000 1970.121623 -EDGE_SE2 758 759 0.549299 -0.065716 -0.139191 11.238871 -6.348958 0.000000 326.618479 0.000000 1926.401990 -EDGE_SE2 759 760 0.597230 0.041521 0.114150 11.646967 11.969500 0.000000 278.475751 0.000000 2013.968527 -EDGE_SE2 760 761 0.024133 -0.000801 0.183513 7939.377412 36011.249548 0.000000 163579.039427 0.000000 1784.818025 -EDGE_SE2 761 762 0.000826 0.001155 1.009551 175055.866129 2941983.942252 0.000000 49446048.586526 0.000000 619.072925 -EDGE_SE2 762 763 0.580729 0.162376 0.292110 11.211099 5.135900 0.000000 274.918098 0.000000 1497.411049 -EDGE_SE2 763 764 0.445705 -0.005172 -0.027993 11.243315 -8.065663 0.000000 503.190215 0.000000 2365.700131 -EDGE_SE2 764 765 0.008361 0.001719 0.638276 244331.555302 525026.230585 0.000000 1128252.931867 0.000000 931.463562 -EDGE_SE2 765 766 0.005344 0.005700 0.998613 53037.087612 289905.348468 0.000000 1584991.089178 0.000000 625.867778 -EDGE_SE2 766 767 0.002645 0.001415 0.929266 1998232.117440 4267585.657123 0.000000 9114261.878773 0.000000 671.669747 -EDGE_SE2 767 768 0.005861 0.004878 0.721092 1261.041135 46349.790224 0.000000 1718749.770688 0.000000 843.979381 -EDGE_SE2 768 769 0.614146 0.107525 0.156299 11.182444 -4.189539 0.000000 257.172044 0.000000 1869.819603 -EDGE_SE2 769 770 0.636280 -0.020581 -0.067664 11.405109 -8.318026 0.000000 246.451563 0.000000 2193.162494 -EDGE_SE2 770 771 0.070000 0.001891 0.559330 5261.360007 8913.246458 0.000000 15142.958000 0.000000 1028.167661 -EDGE_SE2 771 772 0.006744 0.005112 0.865896 64935.054362 294012.600872 0.000000 1331467.660768 0.000000 718.067286 -EDGE_SE2 772 773 0.581158 0.026914 0.085198 11.541618 11.055471 0.000000 295.017264 0.000000 2122.863350 -EDGE_SE2 773 774 0.551019 0.013319 0.021516 11.113346 -0.843063 0.000000 329.161850 0.000000 2395.795043 -EDGE_SE2 774 775 0.004023 0.000830 0.842994 2110367.484852 2837367.218934 0.000000 3814842.025573 0.000000 736.024077 -EDGE_SE2 775 776 0.192558 0.126940 0.615944 13.158809 61.827681 0.000000 1877.920658 0.000000 957.386713 -EDGE_SE2 776 777 0.634282 0.011394 0.058423 11.499517 9.594027 0.000000 248.093510 0.000000 2231.626302 -EDGE_SE2 777 778 0.632295 0.006026 -0.021506 11.341246 -7.412667 0.000000 249.873975 0.000000 2395.841950 -EDGE_SE2 778 779 0.635747 0.009144 0.017394 11.113255 0.711673 0.000000 247.364613 0.000000 2415.247629 -EDGE_SE2 779 780 0.227263 -0.012780 -0.131130 21.872372 -143.298917 0.000000 1919.305655 0.000000 1953.956841 -EDGE_SE2 780 781 0.009670 -0.001829 -0.575170 148004.400196 -361794.734360 0.000000 884479.796277 0.000000 1007.593008 -EDGE_SE2 781 782 0.270298 -0.114336 -0.431075 12.208626 -35.507762 0.000000 1159.889369 0.000000 1220.717636 -EDGE_SE2 782 783 0.611405 -0.011479 -0.001409 11.188373 4.449352 0.000000 267.339350 0.000000 2492.969862 -EDGE_SE2 783 784 0.240113 0.001039 -0.022196 12.323249 -45.688698 0.000000 1733.239839 0.000000 2392.608572 -EDGE_SE2 784 785 0.007959 -0.002926 -0.554001 55828.680061 -272963.055421 0.000000 1334874.506740 0.000000 1035.230954 -EDGE_SE2 785 786 0.004434 -0.000587 -0.590466 980656.281246 -1985068.949325 0.000000 4018282.809762 0.000000 988.305540 -EDGE_SE2 786 787 -0.002001 0.000044 -0.492560 5130982.209484 -10089392.987608 0.000000 19839501.318078 0.000000 1122.215884 -EDGE_SE2 787 788 0.007208 -0.003016 -0.631388 88847.369552 -370943.890957 0.000000 1548921.124356 0.000000 939.345765 -EDGE_SE2 788 789 0.007538 -0.002876 -0.554007 54527.813069 -284219.801981 0.000000 1481775.284964 0.000000 1035.223369 -EDGE_SE2 789 790 0.500376 -0.029812 -0.068057 11.139386 -3.307267 0.000000 397.957897 0.000000 2191.548808 -EDGE_SE2 790 791 0.628826 0.029153 0.097815 11.750061 12.398882 0.000000 251.712715 0.000000 2074.348338 -EDGE_SE2 791 792 0.315704 0.029420 0.702590 333.591596 461.723980 0.000000 672.202381 0.000000 862.422051 -EDGE_SE2 792 793 0.615391 0.019005 0.041490 11.139594 2.682653 0.000000 263.776793 0.000000 2304.781716 -EDGE_SE2 793 794 0.637735 0.016326 0.067824 11.529260 9.895724 0.000000 245.298956 0.000000 2192.505307 -EDGE_SE2 794 795 -0.033087 -0.024410 0.423241 2638.528642 -12185.315173 0.000000 56523.600693 0.000000 1234.193106 -EDGE_SE2 795 796 -0.015774 0.000648 0.650956 163376.535826 197117.295726 0.000000 237853.533044 0.000000 917.210485 -EDGE_SE2 796 797 0.294705 0.074097 0.255423 11.199896 9.754709 0.000000 1082.852214 0.000000 1586.206944 -EDGE_SE2 797 798 0.626641 0.006060 0.046881 11.448159 9.053531 0.000000 254.300351 0.000000 2281.105507 -EDGE_SE2 798 799 0.635666 0.023992 0.062363 11.254358 5.812774 0.000000 246.986103 0.000000 2215.104071 -EDGE_SE2 799 800 0.634468 0.014510 0.069489 11.626291 11.041861 0.000000 247.771504 0.000000 2185.683957 -EDGE_SE2 800 801 0.637847 0.031241 0.082897 11.380932 7.942930 0.000000 244.933506 0.000000 2131.894492 -EDGE_SE2 801 802 0.632634 0.019958 0.054891 11.241159 5.567715 0.000000 249.480486 0.000000 2246.595241 -EDGE_SE2 802 803 0.630127 -0.088612 -0.168062 11.300661 -6.683601 0.000000 246.777787 0.000000 1832.349094 -EDGE_SE2 803 804 0.635077 0.012853 0.053211 11.368430 7.800535 0.000000 247.581479 0.000000 2253.768144 -EDGE_SE2 804 805 0.636519 0.031282 0.073549 11.251547 5.744442 0.000000 246.083247 0.000000 2169.183365 -EDGE_SE2 805 806 0.606343 0.012170 0.038909 11.203672 4.912129 0.000000 271.793935 0.000000 2316.247649 -EDGE_SE2 806 807 0.189729 0.005119 0.292220 201.113736 699.449492 0.000000 2585.968127 0.000000 1497.155415 -EDGE_SE2 807 808 0.003371 0.007327 0.958098 50103.576561 -272947.437303 0.000000 1487266.786417 0.000000 652.035379 -EDGE_SE2 808 809 0.587431 0.097914 0.147917 11.191667 -4.670314 0.000000 281.877711 0.000000 1897.225851 -EDGE_SE2 809 810 0.627956 -0.080646 -0.136964 11.131446 -2.201546 0.000000 249.460063 0.000000 1933.955965 -EDGE_SE2 810 811 0.612576 0.015533 -0.000815 11.285797 -6.674619 0.000000 266.143624 0.000000 2495.929976 -EDGE_SE2 811 812 0.006046 0.000091 0.739463 1201081.516913 1357305.749329 0.000000 1533875.311129 0.000000 826.246472 -EDGE_SE2 812 813 0.018109 0.013231 0.985482 23964.289238 64716.524103 0.000000 174861.749709 0.000000 634.173515 -EDGE_SE2 813 814 0.002006 0.002998 1.002590 3587.558087 165756.923868 0.000000 7682316.480714 0.000000 623.384389 -EDGE_SE2 814 815 0.020425 0.007022 0.928829 67887.614244 99709.570495 0.000000 146482.982663 0.000000 671.974131 -EDGE_SE2 815 816 0.008370 0.002024 0.688367 256339.335199 529144.216869 0.000000 1092335.622944 0.000000 877.013540 -EDGE_SE2 816 817 0.011362 -0.004578 -0.661788 50470.023799 -176289.897436 0.000000 615920.695413 0.000000 905.292186 -EDGE_SE2 817 818 0.201346 -0.091729 -0.483386 17.453139 -113.332496 0.000000 2036.370991 0.000000 1136.139494 -EDGE_SE2 818 819 0.600994 -0.000021 0.016657 11.185144 4.434946 0.000000 276.785971 0.000000 2418.750645 -EDGE_SE2 819 820 0.604107 -0.012016 -0.038590 11.203011 -4.913481 0.000000 273.813863 0.000000 2317.670726 -EDGE_SE2 820 821 0.557707 0.002574 0.018330 11.169482 4.256080 0.000000 321.439373 0.000000 2410.809711 -EDGE_SE2 821 822 0.002019 0.000160 0.773476 9984938.759006 11985389.451377 0.000000 14386651.191718 0.000000 794.857685 -EDGE_SE2 822 823 0.012515 0.017002 0.933412 12.904840 -634.367588 0.000000 224360.656810 0.000000 668.792184 -EDGE_SE2 823 824 0.631778 0.009322 -0.078655 13.193602 -22.229505 0.000000 248.399474 0.000000 2148.695562 -EDGE_SE2 824 825 0.640608 -0.019581 -0.029178 11.111552 0.320195 0.000000 243.449875 0.000000 2360.255512 -EDGE_SE2 825 826 0.635727 0.086901 0.163404 11.286990 6.382404 0.000000 242.719295 0.000000 1847.051069 -EDGE_SE2 826 827 0.633058 -0.024805 -0.048406 11.131451 -2.200226 0.000000 249.121319 0.000000 2274.474191 -EDGE_SE2 827 828 0.640515 0.016631 0.035640 11.132900 2.250508 0.000000 243.562272 0.000000 2330.893209 -EDGE_SE2 828 829 0.604311 -0.016371 -0.038614 11.146008 -3.026498 0.000000 273.593060 0.000000 2317.563615 -EDGE_SE2 829 830 0.611353 -0.005562 -0.007256 11.111980 0.472139 0.000000 267.533817 0.000000 2464.111086 -EDGE_SE2 830 831 0.582292 -0.023325 -0.045648 11.120035 -1.590099 0.000000 294.448496 0.000000 2286.488316 -EDGE_SE2 831 832 0.567969 0.005415 -0.002512 11.154466 -3.599292 0.000000 309.920273 0.000000 2487.487168 -EDGE_SE2 832 833 0.256920 0.000340 0.139017 39.444586 204.467263 0.000000 1486.640047 0.000000 1926.990602 -EDGE_SE2 833 834 0.004768 0.001527 1.059143 1850884.389821 1989766.154557 0.000000 2139092.913935 0.000000 589.612746 -EDGE_SE2 834 835 0.011746 0.005469 0.781010 68236.467078 189689.298378 0.000000 527410.776663 0.000000 788.147120 -EDGE_SE2 835 836 0.015546 0.007972 0.947065 68058.939717 132897.198385 0.000000 259558.927707 0.000000 659.445803 -EDGE_SE2 836 837 0.017648 0.011594 1.040763 44125.577264 89148.384604 0.000000 180165.948528 0.000000 600.281370 -EDGE_SE2 837 838 0.013822 0.005479 0.865867 99632.035075 187458.017071 0.000000 352753.354065 0.000000 718.089607 -EDGE_SE2 838 839 0.001331 -0.000521 -0.216716 1187297.905481 7527754.381697 0.000000 47728231.706064 0.000000 1688.735256 -EDGE_SE2 839 840 0.014201 -0.005576 -0.560094 14691.670684 -78049.547320 0.000000 414963.402725 0.000000 1027.160891 -EDGE_SE2 840 841 0.018508 -0.004844 -0.614349 33618.056740 -89734.585298 0.000000 239613.242398 0.000000 959.279471 -EDGE_SE2 841 842 0.244308 -0.051175 -0.229250 11.937138 -36.275589 0.000000 1604.181092 0.000000 1654.472583 -EDGE_SE2 842 843 0.571578 -0.004308 -0.001490 11.121898 1.783710 0.000000 306.061619 0.000000 2492.566618 -EDGE_SE2 843 844 0.632633 0.008356 -0.006975 11.208334 -4.816449 0.000000 249.718690 0.000000 2465.486516 -EDGE_SE2 844 845 0.634632 -0.005065 -0.013668 11.118782 -1.348758 0.000000 248.265069 0.000000 2433.036002 -EDGE_SE2 845 846 0.637586 0.012768 0.002757 11.181094 -4.052879 0.000000 245.824022 0.000000 2486.271799 -EDGE_SE2 846 847 0.633522 -0.013243 -0.025675 11.116535 -1.135991 0.000000 249.044882 0.000000 2376.405061 -EDGE_SE2 847 848 0.158686 0.003991 0.484189 788.091041 1572.022678 0.000000 3191.702019 0.000000 1134.910441 -EDGE_SE2 848 849 0.002564 0.003351 0.928473 680.469413 61313.177701 0.000000 5616294.276467 0.000000 672.222250 -EDGE_SE2 849 850 0.350597 0.124336 0.356364 11.283371 11.069863 0.000000 722.488046 0.000000 1358.900004 -EDGE_SE2 850 851 0.642798 -0.027661 -0.090713 11.635228 -10.977882 0.000000 241.048137 0.000000 2101.449848 -EDGE_SE2 851 852 0.640836 -0.004293 0.015855 11.229301 5.239393 0.000000 243.375111 0.000000 2422.571276 -EDGE_SE2 852 853 0.610781 0.003140 -0.026553 11.369134 -8.138170 0.000000 267.793422 0.000000 2372.341770 -EDGE_SE2 853 854 0.603861 -0.006364 0.003213 11.160858 3.617435 0.000000 274.156807 0.000000 2484.012095 -EDGE_SE2 854 855 0.610860 0.010420 -0.000693 11.192009 -4.557204 0.000000 267.830171 0.000000 2496.538599 -EDGE_SE2 855 856 0.637641 -0.018640 -0.037084 11.125605 -1.844014 0.000000 245.725607 0.000000 2324.406817 -EDGE_SE2 856 857 0.637311 0.003614 -0.006131 11.143851 -2.774089 0.000000 246.164229 0.000000 2469.624632 -EDGE_SE2 857 858 0.636231 -0.022329 -0.050745 11.168921 -3.690286 0.000000 246.680327 0.000000 2264.359323 -EDGE_SE2 858 859 0.507785 0.004334 -0.003406 11.164814 -4.497374 0.000000 387.747642 0.000000 2483.056613 -EDGE_SE2 859 860 0.002497 0.001745 0.863794 679539.881456 2619251.092498 0.000000 10095943.152469 0.000000 719.687882 -EDGE_SE2 860 861 0.070325 0.071481 0.928711 191.497025 1326.435969 0.000000 9764.823807 0.000000 672.056358 -EDGE_SE2 861 862 0.652508 -0.024736 -0.055891 11.183497 -4.020862 0.000000 234.461196 0.000000 2242.341901 -EDGE_SE2 862 863 0.638309 -0.005836 -0.029014 11.203612 -4.654534 0.000000 245.322644 0.000000 2361.007908 -EDGE_SE2 863 864 0.606532 -0.017964 0.001104 11.356731 7.994878 0.000000 271.342913 0.000000 2494.489128 -EDGE_SE2 864 865 0.604147 0.028266 0.061183 11.165720 3.784052 0.000000 273.324162 0.000000 2220.033054 -EDGE_SE2 865 866 0.579332 -0.011435 0.001982 11.246334 6.225212 0.000000 297.699601 0.000000 2490.119385 -EDGE_SE2 866 867 0.156548 0.001719 0.185575 133.883281 696.034953 0.000000 3957.157327 0.000000 1778.614047 -EDGE_SE2 867 868 0.017881 0.010690 1.037717 52749.955417 96798.086518 0.000000 177676.543047 0.000000 602.077325 -EDGE_SE2 868 869 0.012235 0.005926 0.991656 143324.570378 238746.643887 0.000000 397740.398080 0.000000 630.247818 -EDGE_SE2 869 870 0.002231 -0.000124 1.013097 15395648.131442 8450866.436031 0.000000 4638802.180641 0.000000 616.894084 -EDGE_SE2 870 871 0.001088 0.001679 0.986895 2024.695825 -224276.785530 0.000000 24980373.832027 0.000000 633.271838 -EDGE_SE2 871 872 0.008015 -0.000084 0.694560 653702.249121 768245.705891 0.000000 902886.231030 0.000000 870.614924 -EDGE_SE2 872 873 0.008522 -0.003526 -0.564717 34612.893765 -198701.425503 0.000000 1141058.001437 0.000000 1021.100307 -EDGE_SE2 873 874 0.015858 -0.003778 -0.551904 36802.135033 -111762.498404 0.000000 339519.358447 0.000000 1038.030952 -EDGE_SE2 874 875 0.013521 -0.001487 -0.578534 110429.389804 -217905.190004 0.000000 430036.577843 0.000000 1003.303038 -EDGE_SE2 875 876 0.574406 -0.080596 -0.153354 11.166806 -3.991544 0.000000 297.175644 0.000000 1879.380673 -EDGE_SE2 876 877 0.574770 -0.024813 -0.080909 11.525988 -10.980326 0.000000 301.721640 0.000000 2139.743633 -EDGE_SE2 877 878 0.217632 0.014817 0.389316 219.643265 626.455159 0.000000 1893.056212 0.000000 1295.203276 -EDGE_SE2 878 879 0.647020 0.057742 0.054681 11.377140 -7.747124 0.000000 236.717936 0.000000 2247.489979 -EDGE_SE2 879 880 0.455025 -0.018050 -0.108582 13.346224 -32.372663 0.000000 479.986413 0.000000 2034.250181 -EDGE_SE2 880 881 -0.043409 -0.000133 0.008718 12.813581 300.540520 0.000000 53066.151297 0.000000 2456.973472 -EDGE_SE2 881 882 0.647486 -0.064933 -0.241227 15.572920 -31.371721 0.000000 231.690918 0.000000 1622.697550 -EDGE_SE2 882 883 0.642883 -0.072854 -0.185824 12.322147 -16.564386 0.000000 237.676574 0.000000 1777.868098 -EDGE_SE2 883 884 0.383517 -0.007350 -0.063028 12.396618 -29.287057 0.000000 678.343333 0.000000 2212.333526 -EDGE_SE2 884 885 0.004929 0.003007 0.590777 5527.682570 128525.333864 0.000000 2994400.210829 0.000000 987.919146 -EDGE_SE2 885 886 0.007741 0.006994 1.034072 79878.863906 258839.772996 0.000000 838873.176713 0.000000 604.237070 -EDGE_SE2 886 887 0.010004 0.001000 1.027322 633501.134354 474724.505488 0.000000 355759.975090 0.000000 608.267401 -EDGE_SE2 887 888 0.005011 0.003332 0.999568 444415.889744 1014710.716533 0.000000 2316903.025310 0.000000 625.269895 -EDGE_SE2 888 889 0.005294 0.002083 0.911927 808634.909964 1357982.238784 0.000000 2280571.939853 0.000000 683.907547 -EDGE_SE2 889 890 0.355203 0.095914 0.279682 11.296105 11.600417 0.000000 738.538555 0.000000 1526.637360 -EDGE_SE2 890 891 0.616728 -0.012401 -0.066427 11.650788 -11.642307 0.000000 262.267312 0.000000 2198.253354 -EDGE_SE2 891 892 0.637263 -0.017865 -0.031981 11.114783 -0.928852 0.000000 246.045454 0.000000 2347.451378 -EDGE_SE2 892 893 0.642710 0.035710 0.241471 18.981950 41.834853 0.000000 233.470505 0.000000 1622.059760 -EDGE_SE2 893 894 0.638528 0.083732 0.226070 13.210427 21.873674 0.000000 239.022296 0.000000 1663.065968 -EDGE_SE2 894 895 0.615722 0.105457 0.303953 15.507767 32.534377 0.000000 251.859007 0.000000 1470.334450 -EDGE_SE2 895 896 0.020155 0.000491 0.481484 47934.902135 97432.832108 0.000000 198099.713240 0.000000 1139.058627 -EDGE_SE2 896 897 0.528670 0.158235 0.274351 11.197167 -5.224460 0.000000 328.288174 0.000000 1539.436858 -EDGE_SE2 897 898 0.618615 0.002949 0.017900 11.154262 3.285463 0.000000 261.262932 0.000000 2412.846978 -EDGE_SE2 898 899 0.499807 -0.008373 -0.065092 12.019606 -18.779145 0.000000 399.287489 0.000000 2203.767446 -EDGE_SE2 899 900 0.683722 0.007464 -0.000025 11.135386 -2.218523 0.000000 213.865098 0.000000 2499.875005 -EDGE_SE2 900 901 0.579956 -0.019520 -0.061673 11.335628 -8.008145 0.000000 296.748861 0.000000 2217.984277 -EDGE_SE2 901 902 0.644996 0.015819 0.027799 11.113573 0.751022 0.000000 240.226171 0.000000 2366.593280 -EDGE_SE2 902 903 0.494510 0.003386 -0.042100 12.063405 -19.440085 0.000000 407.959954 0.000000 2302.084267 -EDGE_SE2 903 904 0.005815 0.000708 0.715026 912712.732392 1351574.977076 0.000000 2001492.072759 0.000000 849.960204 -EDGE_SE2 904 905 0.554057 0.035513 0.058326 11.121228 -1.780350 0.000000 324.412517 0.000000 2232.035396 -EDGE_SE2 905 906 0.630376 0.024475 0.068969 11.329543 7.239573 0.000000 251.055279 0.000000 2187.810926 -EDGE_SE2 906 907 0.631021 0.007133 -0.005018 11.175042 -3.916492 0.000000 251.041590 0.000000 2475.097597 -EDGE_SE2 907 908 0.637636 0.001891 0.024788 11.222935 5.123325 0.000000 245.840507 0.000000 2380.520611 -EDGE_SE2 908 909 0.628314 0.001550 -0.017825 11.210816 -4.913046 0.000000 253.205497 0.000000 2413.202580 -EDGE_SE2 909 910 0.147710 -0.043678 -0.369688 39.436166 -343.900479 0.000000 4186.479576 0.000000 1332.590482 -EDGE_SE2 910 911 0.616085 0.011620 0.061065 11.560202 10.634138 0.000000 262.919471 0.000000 2220.526856 -EDGE_SE2 911 912 0.605554 0.006436 0.010902 11.111131 0.071773 0.000000 272.675019 0.000000 2446.368619 -EDGE_SE2 912 913 0.580860 0.003431 0.006628 11.111259 0.205638 0.000000 296.374652 0.000000 2467.186590 -EDGE_SE2 913 914 0.630196 -0.006309 -0.024572 11.162137 -3.503890 0.000000 251.720029 0.000000 2381.524439 -EDGE_SE2 914 915 0.556525 -0.006690 -0.037260 11.309630 -7.863953 0.000000 322.627351 0.000000 2323.618084 -EDGE_SE2 915 916 0.178865 0.104304 0.546671 11.926058 43.487541 0.000000 2331.711773 0.000000 1045.066974 -EDGE_SE2 916 917 0.624756 -0.045966 -0.254265 18.993145 -43.113795 0.000000 246.938496 0.000000 1589.137227 -EDGE_SE2 917 918 0.518933 -0.035276 -0.074995 11.129291 -2.552939 0.000000 369.618783 0.000000 2163.351655 -EDGE_SE2 918 919 0.629099 -0.005797 -0.042335 11.375987 -7.994276 0.000000 252.388154 0.000000 2301.046350 -EDGE_SE2 919 920 0.629899 -0.010656 -0.016202 11.111234 0.171926 0.000000 251.961442 0.000000 2420.917100 -EDGE_SE2 920 921 0.634457 -0.008549 -0.051374 11.451756 -8.983787 0.000000 248.039729 0.000000 2261.650760 -EDGE_SE2 921 922 0.635258 -0.006313 -0.024873 11.163905 -3.534345 0.000000 247.721599 0.000000 2380.125761 -EDGE_SE2 922 923 0.608430 -0.014168 -0.060475 11.469047 -9.619410 0.000000 269.629762 0.000000 2222.998344 -EDGE_SE2 923 924 0.530888 -0.000682 0.019383 11.257903 7.101435 0.000000 354.661710 0.000000 2405.831657 -EDGE_SE2 924 925 0.009664 0.004698 0.510887 2959.553169 50448.307002 0.000000 863189.572650 0.000000 1095.156133 -EDGE_SE2 925 926 0.598427 0.009230 0.018979 11.114501 0.953220 0.000000 279.170216 0.000000 2407.739741 -EDGE_SE2 926 927 0.627907 -0.001812 -0.020475 11.186132 -4.264817 0.000000 253.558182 0.000000 2400.685500 -EDGE_SE2 927 928 0.640773 -0.000139 -0.006135 11.119254 -1.375744 0.000000 243.544155 0.000000 2469.604995 -EDGE_SE2 928 929 0.636560 -0.000176 0.001919 11.112246 0.517244 0.000000 246.784978 0.000000 2490.432549 -EDGE_SE2 929 930 0.640386 -0.014253 -0.078843 11.855260 -13.135681 0.000000 242.981611 0.000000 2147.946760 -EDGE_SE2 930 931 0.635431 -0.020570 -0.076099 11.562880 -10.322123 0.000000 246.953500 0.000000 2158.915046 -EDGE_SE2 931 932 0.639769 -0.010067 -0.055067 11.471607 -9.160668 0.000000 243.895776 0.000000 2245.845776 -EDGE_SE2 932 933 0.631644 -0.015304 -0.059766 11.413371 -8.500896 0.000000 250.193846 0.000000 2225.973780 -EDGE_SE2 933 934 0.504140 0.003029 -0.005219 11.159305 -4.292306 0.000000 393.395672 0.000000 2474.107872 -EDGE_SE2 934 935 0.005622 0.001555 0.696880 504282.663987 1107982.483573 0.000000 2434463.693063 0.000000 868.235915 -EDGE_SE2 935 936 0.001863 0.001286 0.945362 2184651.299423 6152115.682451 0.000000 17324844.542602 0.000000 660.600886 -EDGE_SE2 936 937 0.551720 0.024485 0.062876 11.219817 5.867053 0.000000 327.765518 0.000000 2212.966335 -EDGE_SE2 937 938 0.601673 -0.055314 -0.173492 12.866388 -21.406117 0.000000 272.165004 0.000000 1815.430979 -EDGE_SE2 938 939 0.633059 0.008315 0.027580 11.160855 3.443094 0.000000 249.431085 0.000000 2367.602135 -EDGE_SE2 939 940 0.636273 -0.027491 -0.082722 11.479060 -9.300191 0.000000 246.180789 0.000000 2132.583702 -EDGE_SE2 940 941 0.635944 -0.015109 -0.050698 11.282417 -6.356188 0.000000 246.953620 0.000000 2264.561906 -EDGE_SE2 941 942 0.551791 -0.000493 0.007207 11.131937 2.570602 0.000000 328.415327 0.000000 2464.350846 -EDGE_SE2 942 943 0.644097 -0.001397 0.091523 13.123577 21.416835 0.000000 239.030853 0.000000 2098.332107 -EDGE_SE2 943 944 0.639009 -0.005732 -0.053678 11.578073 -10.437551 0.000000 244.411524 0.000000 2251.770804 -EDGE_SE2 944 945 0.635846 -0.012134 -0.052894 11.381001 -7.978646 0.000000 246.980906 0.000000 2255.125454 -EDGE_SE2 945 946 0.179699 -0.002044 0.066572 29.818272 239.512661 0.000000 3077.654110 0.000000 2197.655692 -EDGE_SE2 946 947 0.406915 0.138311 0.331627 11.119495 2.108463 0.000000 541.380410 0.000000 1409.856218 -EDGE_SE2 947 948 0.579846 -0.001426 -0.021963 11.220001 -5.582502 0.000000 297.312605 0.000000 2393.699690 -EDGE_SE2 948 949 0.604761 -0.049058 -0.159219 12.704160 -20.309811 0.000000 270.041237 0.000000 1860.411550 -EDGE_SE2 949 950 0.636468 -0.025408 -0.243519 20.734999 -46.608998 0.000000 236.840951 0.000000 1616.721292 -EDGE_SE2 950 951 0.637412 -0.014316 -0.075046 11.760145 -12.330103 0.000000 245.353687 0.000000 2163.146402 -EDGE_SE2 951 952 0.637647 0.028692 0.246962 20.543292 46.058094 0.000000 236.016458 0.000000 1607.805725 -EDGE_SE2 952 953 0.635715 0.017895 0.077527 11.686555 11.642681 0.000000 246.671765 0.000000 2153.196604 -EDGE_SE2 953 954 0.632201 -0.012369 -0.013007 11.121379 1.566520 0.000000 250.095671 0.000000 2436.212212 -EDGE_SE2 954 955 0.636040 -0.066402 -0.167279 12.043873 -14.725801 0.000000 243.592003 0.000000 1834.808164 -EDGE_SE2 955 956 0.633169 -0.005303 -0.005934 11.112531 0.581642 0.000000 249.417984 0.000000 2470.592019 -EDGE_SE2 956 957 0.635780 -0.029022 -0.090789 11.591896 -10.635874 0.000000 246.396892 0.000000 2101.157024 -EDGE_SE2 957 958 0.610078 -0.010922 -0.028564 11.140389 -2.745454 0.000000 268.560860 0.000000 2363.074257 -EDGE_SE2 958 959 0.604449 -0.016600 -0.068060 11.543478 -10.642379 0.000000 273.065197 0.000000 2191.536497 -EDGE_SE2 959 960 0.605875 0.054020 0.088370 11.111191 -0.143784 0.000000 270.268197 0.000000 2110.507423 -EDGE_SE2 960 961 0.602054 -0.007561 -0.020089 11.126126 -1.993676 0.000000 275.827437 0.000000 2402.502675 -EDGE_SE2 961 962 0.630743 0.063738 0.073005 11.293528 -6.582439 0.000000 248.635890 0.000000 2171.383420 -EDGE_SE2 962 963 0.629692 0.069822 0.195655 12.835701 20.187165 0.000000 247.411650 0.000000 1748.752064 -EDGE_SE2 963 964 0.639791 -0.008273 -0.057447 11.572861 -10.365475 0.000000 243.797913 0.000000 2235.747685 -EDGE_SE2 964 965 0.633282 -0.006211 -0.001478 11.127639 1.984141 0.000000 249.307749 0.000000 2492.626351 -EDGE_SE2 965 966 0.413197 -0.005006 -0.057147 12.275386 -25.836778 0.000000 584.463061 0.000000 2237.016798 -EDGE_SE2 966 967 0.007510 0.002997 0.859092 325478.163261 626027.365559 0.000000 1204158.381440 0.000000 723.332943 -EDGE_SE2 967 968 0.006374 0.000527 0.902649 1307259.212480 1219284.216016 0.000000 1137250.475138 0.000000 690.593544 -EDGE_SE2 968 969 0.000997 0.000085 0.061289 54733.539945 -2337658.966155 0.000000 99861248.240381 0.000000 2219.589608 -EDGE_SE2 969 970 0.000000 0.000000 -0.000113 11.111116 -0.043944 0.000000 399.999995 0.000000 2499.435096 -EDGE_SE2 970 971 0.361971 0.001286 0.001712 11.113656 -1.383525 0.000000 763.211229 0.000000 2491.461932 -EDGE_SE2 971 972 0.616031 0.005441 0.007131 11.111841 -0.429263 0.000000 263.487396 0.000000 2464.722790 -EDGE_SE2 972 973 0.597393 -0.119850 -0.282715 12.960368 -21.775201 0.000000 267.516438 0.000000 1519.426379 -EDGE_SE2 973 974 0.636084 -0.002771 0.033166 11.443293 8.848623 0.000000 246.819403 0.000000 2342.069601 -EDGE_SE2 974 975 0.636019 0.005980 0.005775 11.114215 -0.856039 0.000000 247.181135 0.000000 2471.373217 -EDGE_SE2 975 976 0.637784 0.010421 0.013983 11.112413 -0.552665 0.000000 245.773095 0.000000 2431.524562 -EDGE_SE2 976 977 0.637920 -0.011711 -0.026304 11.125929 -1.864213 0.000000 245.637352 0.000000 2373.493056 -EDGE_SE2 977 978 0.636711 0.018679 0.044825 11.167625 3.646515 0.000000 246.400847 0.000000 2290.091830 -EDGE_SE2 978 979 0.635616 -0.004880 -0.014420 11.121860 -1.593981 0.000000 247.494628 0.000000 2429.430070 -EDGE_SE2 979 980 0.640402 0.020748 0.043464 11.139636 2.574932 0.000000 243.549790 0.000000 2296.069703 -EDGE_SE2 980 981 0.634599 -0.001102 0.002602 11.115574 1.028911 0.000000 248.309152 0.000000 2487.040602 -EDGE_SE2 981 982 0.582350 0.019314 0.039136 11.121253 1.695467 0.000000 294.536681 0.000000 2315.235788 -EDGE_SE2 982 983 0.606004 -0.005123 -0.005706 11.113084 0.717739 0.000000 272.279670 0.000000 2471.712344 -EDGE_SE2 983 984 0.606209 0.019467 0.054452 11.241333 5.825396 0.000000 271.705807 0.000000 2248.466280 -EDGE_SE2 984 985 0.610191 0.001384 0.017236 11.168792 3.853233 0.000000 268.517439 0.000000 2415.997974 -EDGE_SE2 985 986 0.638807 0.015817 0.032823 11.126330 1.886242 0.000000 244.888150 0.000000 2343.625460 -EDGE_SE2 986 987 0.637113 -0.009662 -0.040633 11.263641 -5.987507 0.000000 246.149046 0.000000 2308.579426 -EDGE_SE2 987 988 0.633843 -0.002158 0.009656 11.151672 3.105391 0.000000 248.863041 0.000000 2452.410392 -EDGE_SE2 988 989 0.637783 0.006714 0.004244 11.120373 -1.474376 0.000000 245.804243 0.000000 2478.914326 -EDGE_SE2 989 990 0.633086 -0.006222 -0.014570 11.116473 -1.130568 0.000000 249.472636 0.000000 2428.711760 -EDGE_SE2 990 991 0.638433 0.009419 0.020655 11.119271 1.382293 0.000000 245.278829 0.000000 2399.838818 -EDGE_SE2 991 992 0.608534 -0.016202 -0.037230 11.140243 -2.745311 0.000000 269.821049 0.000000 2323.752499 -EDGE_SE2 992 993 0.639975 0.012788 0.027838 11.125497 1.830546 0.000000 244.047684 0.000000 2366.413689 -EDGE_SE2 993 994 0.610172 -0.004541 -0.015063 11.126066 -1.962186 0.000000 268.563253 0.000000 2426.353160 -EDGE_SE2 994 995 0.582700 0.014385 0.047816 11.262674 6.550087 0.000000 294.185844 0.000000 2277.036316 -EDGE_SE2 995 996 0.603243 0.013060 0.027432 11.119936 1.525036 0.000000 274.662056 0.000000 2368.284283 -EDGE_SE2 996 997 0.638105 -0.021586 -0.064337 11.329213 -7.143676 0.000000 245.093679 0.000000 2206.895091 -EDGE_SE2 997 998 0.393437 0.003178 0.021791 11.230485 8.704766 0.000000 645.865055 0.000000 2394.505630 -EDGE_SE2 998 999 0.009526 0.010297 0.717647 5765.419520 -53770.217970 0.000000 502458.344534 0.000000 847.368232 -EDGE_SE2 999 1000 0.631982 0.082779 0.148351 11.188179 4.255373 0.000000 246.074510 0.000000 1895.792072 -EDGE_SE2 1000 1001 0.637485 -0.061202 -0.321633 22.788129 -50.803890 0.000000 232.146590 0.000000 1431.259099 -EDGE_SE2 1001 1002 0.630663 0.034533 0.091989 11.444015 8.924103 0.000000 250.338290 0.000000 2096.541587 -EDGE_SE2 1002 1003 0.637376 -0.055899 -0.180665 13.130018 -21.602372 0.000000 242.257264 0.000000 1793.439086 -EDGE_SE2 1003 1004 0.634119 0.020824 0.062770 11.323812 7.101476 0.000000 248.209237 0.000000 2213.407797 -EDGE_SE2 1004 1005 0.602568 0.019724 0.067274 11.426188 9.115028 0.000000 274.805024 0.000000 2194.765624 -EDGE_SE2 1005 1006 0.609599 0.024909 0.082661 11.561301 10.758208 0.000000 268.200258 0.000000 2132.824020 -EDGE_SE2 1006 1007 0.575806 0.024121 0.097394 12.004289 16.068550 0.000000 300.189527 0.000000 2075.940233 -EDGE_SE2 1007 1008 0.296743 0.004461 0.166242 36.620925 167.418708 0.000000 1109.865632 0.000000 1838.072567 -EDGE_SE2 1008 1009 0.169516 0.079531 0.456955 12.060231 51.919506 0.000000 2851.251647 0.000000 1177.735408 -EDGE_SE2 1009 1010 0.635352 0.000090 0.046389 11.616830 10.927244 0.000000 247.219830 0.000000 2283.251111 -EDGE_SE2 1010 1011 0.629760 -0.000818 -0.047667 11.628961 -11.160233 0.000000 251.626406 0.000000 2277.684046 -EDGE_SE2 1011 1012 0.630488 0.001328 0.037830 11.417845 8.582558 0.000000 251.254815 0.000000 2321.066416 -EDGE_SE2 1012 1013 0.638821 0.043192 0.110754 11.546239 10.055629 0.000000 243.492562 0.000000 2026.302298 -EDGE_SE2 1013 1014 0.624005 -0.081360 -0.179557 11.711863 -12.027816 0.000000 251.923335 0.000000 1796.809951 -EDGE_SE2 1014 1015 0.637514 0.038828 0.081332 11.209468 4.796725 0.000000 245.041047 0.000000 2138.069893 -EDGE_SE2 1015 1016 0.781423 -0.009024 0.004462 11.150231 2.443265 0.000000 163.706442 0.000000 2477.838437 -EDGE_SE2 1016 1017 0.603503 0.011706 -0.057436 12.662554 -20.153468 0.000000 272.907609 0.000000 2235.794200 -EDGE_SE2 1017 1018 0.577934 -0.006330 0.007000 11.203996 5.173502 0.000000 299.265589 0.000000 2465.364100 -EDGE_SE2 1018 1019 0.612439 0.031252 0.059177 11.128209 2.087199 0.000000 265.898770 0.000000 2228.450161 -EDGE_SE2 1019 1020 0.633556 -0.016343 -0.014332 11.142340 2.725270 0.000000 248.935660 0.000000 2429.851626 -EDGE_SE2 1020 1021 0.639472 -0.000168 -0.041050 11.499240 -9.510600 0.000000 244.155855 0.000000 2306.730360 -EDGE_SE2 1021 1022 0.070832 0.000271 -0.007651 13.732233 -228.486723 0.000000 19928.608606 0.000000 2462.179597 -EDGE_SE2 1022 1023 0.011155 0.000820 0.086100 139.654009 10135.503712 0.000000 799187.396127 0.000000 2119.338762 -EDGE_SE2 1023 1024 0.645203 -0.002963 0.025849 11.323339 6.969723 0.000000 240.001559 0.000000 2375.598978 -EDGE_SE2 1024 1025 0.648616 0.019366 0.017058 11.148143 -2.895107 0.000000 237.448652 0.000000 2416.843718 -EDGE_SE2 1025 1026 0.180366 -0.000503 0.006661 11.384697 28.945754 0.000000 3073.606781 0.000000 2467.024836 -EDGE_SE2 1026 1027 0.004554 0.001979 0.914665 948112.591095 1716536.548028 0.000000 3107798.392242 0.000000 681.952949 -EDGE_SE2 1027 1028 0.157112 0.092209 0.562259 14.094418 94.590688 0.000000 3010.265300 0.000000 1024.315957 -EDGE_SE2 1028 1029 0.581697 -0.003158 -0.022026 11.189449 -4.719569 0.000000 295.446261 0.000000 2393.404593 -EDGE_SE2 1029 1030 0.602428 -0.021526 -0.077659 11.575380 -11.062953 0.000000 274.727843 0.000000 2152.669156 -EDGE_SE2 1030 1031 0.635032 -0.016817 -0.051435 11.258521 -5.904986 0.000000 247.654252 0.000000 2261.388344 -EDGE_SE2 1031 1032 0.639363 0.000529 0.006615 11.118933 1.351453 0.000000 244.619567 0.000000 2467.250316 -EDGE_SE2 1032 1033 0.641217 -0.014716 -0.042294 11.197935 -4.487022 0.000000 242.999818 0.000000 2301.227383 -EDGE_SE2 1033 1034 0.158807 -0.001999 -0.209870 162.997809 -759.872169 0.000000 3812.666625 0.000000 1707.900606 -EDGE_SE2 1034 1035 0.008238 -0.003621 -0.612225 47839.602807 -238285.590348 0.000000 1187170.073357 0.000000 961.808711 -EDGE_SE2 1035 1036 -0.001359 0.001797 -0.564077 2434530.032209 6484761.501388 0.000000 17273293.058299 0.000000 1021.936120 -EDGE_SE2 1036 1037 0.377894 -0.111886 -0.234247 12.927670 33.853486 0.000000 642.006396 0.000000 1641.103033 -EDGE_SE2 1037 1038 0.646416 0.075596 0.094513 11.219032 -4.926286 0.000000 235.981250 0.000000 2086.883283 -EDGE_SE2 1038 1039 0.688482 -0.025514 -0.028564 11.125452 1.691699 0.000000 210.663547 0.000000 2363.074257 -EDGE_SE2 1039 1040 -0.001379 -0.000331 0.637825 7632266.679736 17921038.113983 0.000000 42079787.422993 0.000000 931.976618 -EDGE_SE2 1040 1041 -0.001323 0.000722 1.029242 43947061.658526 1853405.592364 0.000000 78175.908225 0.000000 607.116902 -EDGE_SE2 1041 1042 0.008412 0.001092 0.999819 812869.525001 684736.258072 0.000000 576819.734984 0.000000 625.113140 -EDGE_SE2 1042 1043 0.010022 0.000228 0.981327 666387.833541 467987.047537 0.000000 328671.866042 0.000000 636.836128 -EDGE_SE2 1043 1044 -0.013611 -0.010605 1.005709 38168.445431 106580.996550 0.000000 297712.956067 0.000000 621.446905 -EDGE_SE2 1044 1045 -0.002205 0.000124 -0.113838 68490.084727 -1183057.512679 0.000000 20438767.774721 0.000000 2015.095849 -EDGE_SE2 1045 1046 -0.013495 0.002112 -0.385242 27867.951272 -118972.940165 0.000000 508129.060237 0.000000 1302.832870 -EDGE_SE2 1046 1047 -0.019733 0.005898 -0.555401 16179.611132 -59582.091055 0.000000 219575.422578 0.000000 1033.368600 -EDGE_SE2 1047 1048 0.344577 -0.119470 -0.312747 11.437653 15.549100 0.000000 751.519224 0.000000 1450.701098 -EDGE_SE2 1048 1049 0.648714 0.010953 0.017287 11.111148 0.091735 0.000000 237.558159 0.000000 2415.755736 -EDGE_SE2 1049 1050 0.646643 0.027376 0.075802 11.366332 7.617483 0.000000 238.466970 0.000000 2160.107247 -EDGE_SE2 1050 1051 0.640459 -0.024485 -0.073431 11.399152 -8.175325 0.000000 243.147148 0.000000 2169.660298 -EDGE_SE2 1051 1052 0.610691 0.014345 0.058571 11.427186 9.005158 0.000000 267.673485 0.000000 2231.002333 -EDGE_SE2 1052 1053 0.402418 -0.011887 -0.047093 11.297991 -10.639018 0.000000 616.787282 0.000000 2280.181912 -EDGE_SE2 1053 1054 0.003611 0.000205 0.781659 3360883.673888 3794299.768961 0.000000 4283634.029810 0.000000 787.573032 -EDGE_SE2 1054 1055 -0.004781 -0.004680 1.092196 217607.587361 662404.612456 0.000000 2016495.376692 0.000000 571.130228 -EDGE_SE2 1055 1056 -0.018363 -0.010043 1.033833 59014.075212 99936.588877 0.000000 169279.247866 0.000000 604.379088 -EDGE_SE2 1056 1057 -0.018154 -0.006925 1.003259 94181.986455 126785.732418 0.000000 170707.431880 0.000000 622.968093 -EDGE_SE2 1057 1058 0.000938 0.000345 0.933655 30225249.079874 45961533.817447 0.000000 69890696.274135 0.000000 668.624102 -EDGE_SE2 1058 1059 0.584768 -0.021106 -0.077373 11.589927 -11.588453 0.000000 291.578229 0.000000 2153.812205 -EDGE_SE2 1059 1060 0.639269 -0.001644 0.007968 11.137057 2.461692 0.000000 244.671355 0.000000 2460.631159 -EDGE_SE2 1060 1061 0.453408 -0.013544 -0.118843 14.861134 -42.033048 0.000000 482.248782 0.000000 1997.108732 -EDGE_SE2 1061 1062 0.018407 -0.004707 -0.560522 25818.783584 -80519.505627 0.000000 251230.619305 0.000000 1026.597536 -EDGE_SE2 1062 1063 -0.002214 0.000350 -0.593849 3568021.016682 -7633088.462779 0.000000 16329573.254319 0.000000 984.114566 -EDGE_SE2 1063 1064 0.301240 -0.082154 -0.262828 11.122946 3.465125 0.000000 1025.683739 0.000000 1567.659011 -EDGE_SE2 1064 1065 0.616850 0.043972 0.123884 11.806351 13.175109 0.000000 260.785525 0.000000 1979.233494 -EDGE_SE2 1065 1066 0.592225 -0.017770 -0.054423 11.274422 -6.684300 0.000000 284.699249 0.000000 2248.589962 -EDGE_SE2 1066 1067 0.012072 0.002120 0.435817 44661.394679 166520.359722 0.000000 621038.078606 0.000000 1212.667746 -EDGE_SE2 1067 1068 0.005144 0.001599 0.677089 463864.684926 1176104.562755 0.000000 2982033.931716 0.000000 888.848590 -EDGE_SE2 1068 1069 0.004939 0.001172 0.172450 14196.268745 -234184.920951 0.000000 3866205.524763 0.000000 1818.659296 -EDGE_SE2 1069 1070 0.007958 -0.000773 -0.535379 282034.324000 -601390.067166 0.000000 1282423.325271 0.000000 1060.495466 -EDGE_SE2 1070 1071 0.555140 -0.067868 -0.125252 11.115112 -1.111199 0.000000 319.703282 0.000000 1974.424001 -EDGE_SE2 1071 1072 0.529254 -0.007703 -0.066861 12.056408 -18.055610 0.000000 355.981837 0.000000 2196.465215 -EDGE_SE2 1072 1073 -0.002029 0.000845 -0.507518 262958.959876 -2318685.557147 0.000000 20446281.115523 0.000000 1100.056511 -EDGE_SE2 1073 1074 0.561059 -0.025535 -0.032676 11.161259 3.916370 0.000000 316.967702 0.000000 2344.292731 -EDGE_SE2 1074 1075 0.609431 -0.004618 0.018200 11.282578 6.650541 0.000000 269.060256 0.000000 2411.425356 -EDGE_SE2 1075 1076 0.065495 0.001481 0.413124 3385.912605 8198.067984 0.000000 19925.858335 0.000000 1251.928321 -EDGE_SE2 1076 1077 0.014156 0.014258 0.821400 271.376246 8025.080869 0.000000 247458.480551 0.000000 753.579966 -EDGE_SE2 1077 1078 0.639455 0.059020 0.049931 11.521069 -9.730785 0.000000 242.081388 0.000000 2267.871749 -EDGE_SE2 1078 1079 0.600624 0.018085 0.067237 11.477555 9.863097 0.000000 276.583452 0.000000 2194.917807 -EDGE_SE2 1079 1080 -0.000999 -0.000009 -0.477168 21861087.771847 -41382475.748765 0.000000 78336011.010556 0.000000 1145.724571 -EDGE_SE2 1080 1081 0.531360 -0.067180 -0.117428 11.134556 2.812802 0.000000 348.582744 0.000000 2002.169815 -EDGE_SE2 1081 1082 0.224996 0.001967 0.288640 161.010437 521.488265 0.000000 1825.328808 0.000000 1505.486248 -EDGE_SE2 1082 1083 -0.010460 -0.011699 1.057628 18726.686416 85143.154920 0.000000 387354.631781 0.000000 590.481488 -EDGE_SE2 1083 1084 0.006499 0.006279 0.991072 59854.087388 264007.010053 0.000000 1164720.918244 0.000000 630.617587 -EDGE_SE2 1084 1085 0.020056 0.011249 0.977075 38176.449616 75898.227624 0.000000 150947.567649 0.000000 639.578299 -EDGE_SE2 1085 1086 0.570700 0.124357 0.228493 11.165939 3.931749 0.000000 293.059740 0.000000 1656.511362 -EDGE_SE2 1086 1087 0.610443 -0.014761 -0.013224 11.141951 2.815599 0.000000 268.167634 0.000000 2435.168807 -EDGE_SE2 1087 1088 0.601056 0.009570 -0.017713 11.411487 -8.927269 0.000000 276.432474 0.000000 2413.733758 -EDGE_SE2 1088 1089 0.071683 -0.000572 -0.098521 170.122570 -1751.356223 0.000000 19300.592801 0.000000 2071.681742 -EDGE_SE2 1089 1090 0.001412 -0.000123 -0.621871 12937756.646628 -21836745.706848 0.000000 36856777.365825 0.000000 950.402110 -EDGE_SE2 1090 1091 0.549397 -0.084430 -0.180259 11.352156 -8.676436 0.000000 323.419744 0.000000 1794.673157 -EDGE_SE2 1091 1092 0.637703 -0.006996 -0.017526 11.121203 -1.539154 0.000000 245.862562 0.000000 2414.621027 -EDGE_SE2 1092 1093 0.588555 -0.015042 -0.067587 11.600931 -11.646012 0.000000 288.008196 0.000000 2193.478870 -EDGE_SE2 1093 1094 0.004150 -0.003600 -0.406987 303638.185583 955915.435697 0.000000 3009539.565685 0.000000 1262.873468 -EDGE_SE2 1094 1095 0.025922 -0.007302 -0.593448 13559.452360 -41040.960104 0.000000 124333.371329 0.000000 984.609944 -EDGE_SE2 1095 1096 0.013621 -0.004396 -0.574854 32930.237834 -122414.831277 0.000000 455229.472232 0.000000 1007.997402 -EDGE_SE2 1096 1097 0.359533 -0.076883 -0.217554 11.145668 -5.017901 0.000000 739.746128 0.000000 1686.411461 -EDGE_SE2 1097 1098 0.655276 -0.022381 -0.058348 11.240870 -5.359644 0.000000 232.489049 0.000000 2231.942602 -EDGE_SE2 1098 1099 0.601562 -0.024926 -0.098508 11.973250 -15.083436 0.000000 275.001216 0.000000 2071.731935 -EDGE_SE2 1099 1100 0.019767 0.000659 0.359334 26235.559183 77565.286776 0.000000 229429.617699 0.000000 1352.968387 -EDGE_SE2 1100 1101 0.259176 0.070164 0.262689 11.115050 -2.328152 0.000000 1387.055621 0.000000 1568.004174 -EDGE_SE2 1101 1102 0.009767 -0.003058 -0.397627 8459.012576 -89410.542255 0.000000 946310.626975 0.000000 1279.845202 -EDGE_SE2 1102 1103 0.624811 -0.021021 -0.035899 11.112369 -0.554908 0.000000 255.864408 0.000000 2329.727795 -EDGE_SE2 1103 1104 0.653192 -0.005160 -0.029757 11.217748 -4.878085 0.000000 234.257657 0.000000 2357.602064 -EDGE_SE2 1104 1105 0.643770 -0.007193 -0.019886 11.128584 -2.005277 0.000000 241.242039 0.000000 2403.459167 -EDGE_SE2 1105 1106 0.496058 -0.003395 -0.027229 11.275339 -8.055101 0.000000 406.199361 0.000000 2369.220411 -EDGE_SE2 1106 1107 0.007526 0.002867 0.253134 18856.773417 -169404.055090 0.000000 1522787.727562 0.000000 1592.007032 -EDGE_SE2 1107 1108 0.625868 0.043204 0.005957 12.073074 -15.257830 0.000000 253.117791 0.000000 2470.479046 -EDGE_SE2 1108 1109 0.646003 -0.046291 -0.106175 11.383719 -7.866802 0.000000 238.127651 0.000000 2043.112734 -EDGE_SE2 1109 1110 0.614215 -0.005255 -0.051510 11.579361 -10.894385 0.000000 264.581538 0.000000 2261.065764 -EDGE_SE2 1110 1111 0.553199 -0.082221 -0.103442 11.711068 13.593477 0.000000 319.104424 0.000000 2053.246012 -EDGE_SE2 1111 1112 0.569389 0.118635 0.343250 16.481962 38.719218 0.000000 290.243375 0.000000 1385.563104 -EDGE_SE2 1112 1113 0.640195 -0.016890 -0.097447 12.284559 -16.483251 0.000000 242.648861 0.000000 2075.739728 -EDGE_SE2 1113 1114 0.617738 0.000372 0.015293 11.165263 3.685922 0.000000 262.000150 0.000000 2425.253974 -EDGE_SE2 1114 1115 0.584111 0.002651 -0.017913 11.253226 -6.328745 0.000000 292.947350 0.000000 2412.785348 -EDGE_SE2 1115 1116 0.648872 0.022176 0.034505 11.111138 0.077459 0.000000 237.232680 0.000000 2336.010662 -EDGE_SE2 1116 1117 0.098251 0.000884 -0.129855 209.328151 -1418.352583 0.000000 10160.208546 0.000000 1958.369267 -EDGE_SE2 1117 1118 0.002069 -0.000845 -0.611494 987546.746516 -4336045.136437 0.000000 19038602.480542 0.000000 962.681493 -EDGE_SE2 1118 1119 -0.002904 0.000748 -0.435035 368477.951626 -1990623.945676 0.000000 10754258.868008 0.000000 1213.989755 -EDGE_SE2 1119 1120 0.606241 -0.045059 -0.065468 11.130843 2.262698 0.000000 270.573321 0.000000 2202.212316 -EDGE_SE2 1120 1121 0.209582 -0.004500 -0.120622 33.301618 -223.063126 0.000000 2253.383418 0.000000 1990.772900 -EDGE_SE2 1121 1122 0.003037 -0.001969 -0.554282 3351.615045 159642.761466 0.000000 7629342.430661 0.000000 1034.857076 -EDGE_SE2 1122 1123 0.587650 -0.008795 0.015249 11.365183 8.406488 0.000000 289.256608 0.000000 2425.464195 -EDGE_SE2 1123 1124 0.579143 0.038116 0.096775 11.386604 8.868243 0.000000 296.584474 0.000000 2078.284141 -EDGE_SE2 1124 1125 0.646108 -0.002624 0.011822 11.168733 3.627591 0.000000 239.485218 0.000000 2441.921916 -EDGE_SE2 1125 1126 0.089655 0.001862 0.336774 1211.106301 3670.039910 0.000000 11235.483551 0.000000 1399.020340 -EDGE_SE2 1126 1127 -0.000544 0.000812 1.050094 84031228.496092 -41585087.528682 0.000000 20579500.003262 0.000000 594.829446 -EDGE_SE2 1127 1128 -0.002103 -0.000314 0.980680 12093669.618717 11006276.376659 0.000000 10016675.597149 0.000000 637.252248 -EDGE_SE2 1128 1129 0.011252 0.005103 1.008728 198520.561371 301067.442842 0.000000 456622.144090 0.000000 619.580502 -EDGE_SE2 1129 1130 0.583423 0.017793 0.012045 11.207158 -5.207167 0.000000 293.417741 0.000000 2440.845899 -EDGE_SE2 1130 1131 0.750481 -0.194337 -0.435123 16.183680 -27.603353 0.000000 161.320023 0.000000 1213.840879 -EDGE_SE2 1131 1132 0.640243 -0.002464 -0.021306 11.182068 -4.064051 0.000000 243.880425 0.000000 2396.780386 -EDGE_SE2 1132 1133 0.584277 -0.021867 -0.040363 11.113568 -0.831424 0.000000 292.516553 0.000000 2309.777849 -EDGE_SE2 1133 1134 0.266576 -0.000300 -0.098860 24.404478 -135.580323 0.000000 1393.907817 0.000000 2070.404863 -EDGE_SE2 1134 1135 0.009102 -0.002652 -0.559816 82791.558254 -291964.753439 0.000000 1029764.152962 0.000000 1027.527058 -EDGE_SE2 1135 1136 0.002258 -0.003305 -0.565768 971762.123150 2263140.796874 0.000000 5270709.266319 0.000000 1019.729968 -EDGE_SE2 1136 1137 0.306973 -0.042413 -0.186154 13.568352 -50.253896 0.000000 1038.871344 0.000000 1776.878994 -EDGE_SE2 1137 1138 0.654763 -0.011031 -0.017798 11.111312 -0.211469 0.000000 233.189098 0.000000 2413.330616 -EDGE_SE2 1138 1139 0.527941 0.000918 -0.077053 13.265063 -27.280422 0.000000 356.625570 0.000000 2155.092221 -EDGE_SE2 1139 1140 -0.002013 0.000175 -0.486547 3709493.048971 -8779833.609002 0.000000 20780669.837336 0.000000 1131.312847 -EDGE_SE2 1140 1141 0.002239 -0.000031 -0.555810 5310315.218372 -8816646.759236 0.000000 14638204.801536 0.000000 1032.825356 -EDGE_SE2 1141 1142 0.372375 -0.136555 -0.370794 11.343901 -12.055726 0.000000 635.453819 0.000000 1330.440997 -EDGE_SE2 1142 1143 0.629856 0.033762 0.085383 11.354434 7.641679 0.000000 251.102091 0.000000 2122.139741 -EDGE_SE2 1143 1144 0.612945 -0.010504 -0.034290 11.186135 -4.373095 0.000000 266.015507 0.000000 2336.981945 -EDGE_SE2 1144 1145 0.611105 -0.003802 -0.029142 11.245917 -5.880472 0.000000 267.628650 0.000000 2360.420642 -EDGE_SE2 1145 1146 0.609486 -0.000759 0.016125 11.188979 4.482263 0.000000 269.120272 0.000000 2421.284019 -EDGE_SE2 1146 1147 0.610275 0.036873 0.068649 11.128787 2.128847 0.000000 267.508800 0.000000 2189.121374 -EDGE_SE2 1147 1148 0.611337 -0.001965 0.012226 11.172242 3.959007 0.000000 267.506715 0.000000 2439.973063 -EDGE_SE2 1148 1149 0.074700 0.001638 0.503169 3846.534249 7344.890200 0.000000 14076.680961 0.000000 1106.431132 -EDGE_SE2 1149 1150 -0.006116 -0.002785 0.988331 626799.870889 997506.113526 0.000000 1587497.215478 0.000000 632.357453 -EDGE_SE2 1150 1151 0.014648 0.006739 0.987862 107400.301813 172549.549763 0.000000 277258.261675 0.000000 632.655875 -EDGE_SE2 1151 1152 0.009432 0.009802 1.036217 28480.057962 120720.157191 0.000000 511914.710091 0.000000 602.964704 -EDGE_SE2 1152 1153 0.010437 0.002034 0.996659 458897.357799 441929.724577 0.000000 425610.882022 0.000000 627.093176 -EDGE_SE2 1153 1154 0.277143 0.156011 0.537087 11.691675 23.815732 0.000000 988.073623 0.000000 1058.139946 -EDGE_SE2 1154 1155 0.634179 -0.005082 -0.053384 11.599710 -10.761566 0.000000 248.138569 0.000000 2253.027920 -EDGE_SE2 1155 1156 0.609122 -0.005838 0.006338 11.176606 4.113232 0.000000 269.430259 0.000000 2468.608751 -EDGE_SE2 1156 1157 0.580367 0.023367 0.106616 12.366206 18.881213 0.000000 295.153466 0.000000 2041.484648 -EDGE_SE2 1157 1158 0.608842 -0.050707 -0.133293 11.757739 -12.869932 0.000000 267.263428 0.000000 1946.505325 -EDGE_SE2 1158 1159 0.600995 -0.037895 -0.099499 11.464087 -9.658719 0.000000 275.409224 0.000000 2067.999033 -EDGE_SE2 1159 1160 0.637109 -0.021604 -0.142588 13.876030 -25.338115 0.000000 243.313239 0.000000 1914.964342 -EDGE_SE2 1160 1161 0.638306 -0.057065 -0.094949 11.118890 -1.344463 0.000000 243.484624 0.000000 2085.221653 -EDGE_SE2 1161 1162 0.639583 0.008532 0.053343 11.484272 9.323139 0.000000 244.042318 0.000000 2253.203316 -EDGE_SE2 1162 1163 0.646089 0.001306 -0.009750 11.142767 -2.689017 0.000000 239.527759 0.000000 2451.953812 -EDGE_SE2 1163 1164 0.642172 0.018842 0.080564 11.717339 11.822667 0.000000 241.677018 0.000000 2141.110196 -EDGE_SE2 1164 1165 0.530061 0.001899 -0.020695 11.314294 -8.367588 0.000000 355.709513 0.000000 2399.650727 -EDGE_SE2 1165 1166 0.004850 0.001220 0.493564 239307.954224 948357.988051 0.000000 3758451.305300 0.000000 1120.707645 -EDGE_SE2 1166 1167 0.000199 0.000971 0.944839 17209450.782475 -38137417.374455 0.000000 84515406.833935 0.000000 660.956228 -EDGE_SE2 1167 1168 0.004314 0.002779 0.911345 419892.583640 1190803.974162 0.000000 3377188.237646 0.000000 684.324107 -EDGE_SE2 1168 1169 0.046124 0.045485 0.829043 72.075115 1203.501414 0.000000 23769.649842 0.000000 747.295174 -EDGE_SE2 1169 1170 0.595970 0.008443 0.008952 11.118461 -1.409691 0.000000 281.483079 0.000000 2455.833943 -EDGE_SE2 1170 1171 0.643652 0.016020 0.034262 11.131351 2.158066 0.000000 241.208530 0.000000 2337.108483 -EDGE_SE2 1171 1172 0.608254 -0.008594 -0.059650 11.647713 -11.779607 0.000000 269.699888 0.000000 2226.461162 -EDGE_SE2 1172 1173 0.635753 0.004699 0.011813 11.115733 1.045017 0.000000 247.395251 0.000000 2441.965358 -EDGE_SE2 1173 1174 0.642740 -0.015092 -0.065577 11.519977 -9.706025 0.000000 241.521390 0.000000 2201.761802 -EDGE_SE2 1174 1175 0.635529 -0.015560 -0.030331 11.119207 -1.383209 0.000000 247.431148 0.000000 2354.975943 -EDGE_SE2 1175 1176 0.639892 -0.002591 -0.040430 11.419513 -8.473235 0.000000 243.910274 0.000000 2309.480375 -EDGE_SE2 1176 1177 0.631909 0.000862 0.005069 11.114395 0.886514 0.000000 250.429122 0.000000 2474.846416 -EDGE_SE2 1177 1178 0.638012 -0.011209 -0.043943 11.274194 -6.181646 0.000000 245.425622 0.000000 2293.963142 -EDGE_SE2 1178 1179 0.631478 0.010553 0.032543 11.171171 3.792944 0.000000 250.644522 0.000000 2344.896698 -EDGE_SE2 1179 1180 0.271033 0.000088 -0.003969 11.136010 -5.798071 0.000000 1361.277228 0.000000 2480.272525 -EDGE_SE2 1180 1181 0.006369 0.000562 0.838184 1136739.900794 1219876.425763 0.000000 1309117.124470 0.000000 739.881291 -EDGE_SE2 1181 1182 0.043362 0.037473 0.721003 13.218472 253.246510 0.000000 30444.337192 0.000000 844.066675 -EDGE_SE2 1182 1183 0.631233 0.006864 0.028504 11.185650 4.227407 0.000000 250.864920 0.000000 2363.349975 -EDGE_SE2 1183 1184 0.641740 0.028391 0.073043 11.303273 6.663120 0.000000 242.151864 0.000000 2171.229631 -EDGE_SE2 1184 1185 0.636568 -0.012623 -0.029018 11.131008 -2.164911 0.000000 246.663116 0.000000 2360.989552 -EDGE_SE2 1185 1186 0.637011 0.023759 0.069721 11.358319 7.617657 0.000000 245.847739 0.000000 2184.736002 -EDGE_SE2 1186 1187 0.658018 -0.006443 -0.033774 11.237521 -5.269863 0.000000 230.804698 0.000000 2339.315499 -EDGE_SE2 1187 1188 0.632380 0.009510 0.021371 11.120695 1.513079 0.000000 249.993325 0.000000 2396.475334 -EDGE_SE2 1188 1189 0.635906 -0.012539 0.021673 11.515314 9.760309 0.000000 246.794097 0.000000 2395.058778 -EDGE_SE2 1189 1190 0.298422 -0.000493 0.007995 11.214542 10.722954 0.000000 1122.783078 0.000000 2460.499340 -EDGE_SE2 1190 1191 -0.001378 -0.000184 0.920177 25978781.998107 25880314.470994 0.000000 25782242.304073 0.000000 678.043383 -EDGE_SE2 1191 1192 0.072942 0.060647 0.797518 130.506556 1145.096181 0.000000 10993.483679 0.000000 773.736998 -EDGE_SE2 1192 1193 0.612651 -0.026766 -0.132178 13.102394 -22.437131 0.000000 263.925490 0.000000 1950.341157 -EDGE_SE2 1193 1194 0.586582 0.016272 0.041820 11.166533 3.933966 0.000000 290.352323 0.000000 2303.321852 -EDGE_SE2 1194 1195 0.636169 0.007659 0.052000 11.487698 9.418662 0.000000 246.677289 0.000000 2258.959939 -EDGE_SE2 1195 1196 0.637063 -0.002513 -0.173199 17.787125 -39.066310 0.000000 239.717067 0.000000 1816.337880 -EDGE_SE2 1196 1197 0.631038 0.007284 0.010757 11.111259 -0.188614 0.000000 251.090831 0.000000 2447.070566 -EDGE_SE2 1197 1198 0.639335 0.035252 0.257911 20.557528 45.933130 0.000000 234.460604 0.000000 1579.938488 -EDGE_SE2 1198 1199 0.625974 -0.039991 -0.215702 16.676523 -36.355580 0.000000 248.600846 0.000000 1691.553532 -EDGE_SE2 1199 1200 0.642662 0.020896 0.068112 11.403588 8.210051 0.000000 241.573905 0.000000 2191.323116 -EDGE_SE2 1200 1201 0.632369 0.008692 0.054836 11.514278 9.806016 0.000000 249.617869 0.000000 2246.829525 -EDGE_SE2 1201 1202 0.636732 0.009332 0.021910 11.123506 1.708394 0.000000 246.587725 0.000000 2393.947989 -EDGE_SE2 1202 1203 0.605583 0.016194 -0.091218 14.730772 -30.544741 0.000000 268.864904 0.000000 2099.505256 -EDGE_SE2 1203 1204 0.604704 -0.076543 -0.148349 11.241024 -5.788533 0.000000 269.030303 0.000000 1895.798676 -EDGE_SE2 1204 1205 0.579744 0.012270 0.028212 11.125345 2.018565 0.000000 297.379849 0.000000 2364.692492 -EDGE_SE2 1205 1206 0.604024 0.022981 0.059672 11.234092 5.681316 0.000000 273.569799 0.000000 2226.368715 -EDGE_SE2 1206 1207 0.628833 -0.063349 -0.087865 11.148708 2.998873 0.000000 250.310531 0.000000 2112.467324 -EDGE_SE2 1207 1208 0.641879 0.018435 0.062871 11.381019 7.898378 0.000000 242.243300 0.000000 2212.987156 -EDGE_SE2 1208 1209 0.636239 0.001912 -0.003661 11.121595 -1.572688 0.000000 247.023047 0.000000 2481.795033 -EDGE_SE2 1209 1210 0.630195 0.024749 0.018688 11.212716 -4.940152 0.000000 251.306983 0.000000 2409.115535 -EDGE_SE2 1210 1211 0.632941 -0.047678 -0.070430 11.116473 1.127530 0.000000 248.202543 0.000000 2181.842838 -EDGE_SE2 1211 1212 0.633914 0.009606 0.052050 11.434554 8.761975 0.000000 248.470147 0.000000 2258.745224 -EDGE_SE2 1212 1213 0.635719 0.026579 0.075094 11.372749 7.851816 0.000000 246.746209 0.000000 2162.953249 -EDGE_SE2 1213 1214 0.748508 -0.025001 -0.220810 16.915079 -30.604005 0.000000 172.484342 0.000000 1677.427863 -EDGE_SE2 1214 1215 0.609440 0.015872 0.060134 11.410886 8.788375 0.000000 268.756514 0.000000 2224.428662 -EDGE_SE2 1215 1216 0.569604 0.086391 0.218432 12.447317 19.645507 0.000000 299.948223 0.000000 1683.981886 -EDGE_SE2 1216 1217 0.604098 -0.020910 -0.018798 11.176666 4.148410 0.000000 273.628656 0.000000 2408.595337 -EDGE_SE2 1217 1218 0.590246 0.008252 -0.050669 12.262477 -17.784784 0.000000 285.827155 0.000000 2264.686919 -EDGE_SE2 1218 1219 0.650992 0.006557 0.030598 11.205817 4.613431 0.000000 235.846718 0.000000 2353.755880 -EDGE_SE2 1219 1220 0.586496 0.026678 0.090738 11.682801 12.616550 0.000000 289.544235 0.000000 2101.353517 -EDGE_SE2 1220 1221 -0.001846 -0.000482 -0.452753 11628909.160981 -13576008.003722 0.000000 15849147.678198 0.000000 1184.558318 -EDGE_SE2 1221 1222 0.012937 -0.005157 -0.597307 24124.307745 -108858.692621 0.000000 491452.172995 0.000000 979.857795 -EDGE_SE2 1222 1223 0.011537 -0.003845 -0.559627 37585.948232 -154900.759550 0.000000 638583.281939 0.000000 1027.776110 -EDGE_SE2 1223 1224 0.574470 -0.089064 -0.182908 11.352146 -8.281702 0.000000 295.661931 0.000000 1786.644187 -EDGE_SE2 1224 1225 0.625700 0.003903 0.013764 11.124947 1.838454 0.000000 255.403355 0.000000 2432.575223 -EDGE_SE2 1225 1226 0.106504 -0.000109 -0.016731 13.283390 -138.281257 0.000000 8813.714781 0.000000 2418.398573 -EDGE_SE2 1226 1227 0.000000 0.000000 -0.000662 11.111282 -0.257444 0.000000 399.999830 0.000000 2496.693284 -EDGE_SE2 19 166 -2.459689 0.241111 0.252800 11.731352 1.696454 0.000000 15.751178 0.000000 1592.856013 -EDGE_SE2 19 172 1.067903 0.915786 0.149470 22.211594 -17.729393 0.000000 39.428022 0.000000 1892.102792 -EDGE_SE2 25 172 -2.539634 0.852630 -0.029860 11.348228 0.783018 0.000000 13.696833 0.000000 2357.130503 -EDGE_SE2 25 178 1.225223 0.672079 -0.102480 24.051651 -18.745770 0.000000 38.266385 0.000000 2056.830811 -EDGE_SE2 32 178 -2.020007 -0.239771 0.715180 15.237484 6.070047 0.000000 20.040376 0.000000 849.807581 -EDGE_SE2 32 183 -0.092559 0.424181 0.041600 515.079071 88.191252 0.000000 26.544031 0.000000 2304.294940 -EDGE_SE2 44 189 -2.265706 -0.570857 0.197720 11.128469 -0.353246 0.000000 18.300012 0.000000 1742.727183 -EDGE_SE2 44 195 1.302289 -0.133004 -0.005280 11.549680 4.530716 0.000000 57.916501 0.000000 2473.807626 -EDGE_SE2 50 195 -2.374379 -0.253682 0.216120 11.188114 0.699234 0.000000 17.460612 0.000000 1690.390904 -EDGE_SE2 50 201 1.291572 0.086248 -0.050700 11.777215 -5.648747 0.000000 59.014090 0.000000 2264.553285 -EDGE_SE2 50 203 2.550695 0.035722 -0.084650 11.152401 -0.417172 0.000000 15.326014 0.000000 2125.008969 -EDGE_SE2 61 203 -2.852494 0.122053 0.077870 11.127858 0.138148 0.000000 12.250754 0.000000 2151.826441 -EDGE_SE2 61 209 0.730780 0.072970 0.008890 12.538871 -15.710166 0.000000 183.975779 0.000000 2456.135792 -EDGE_SE2 67 209 -2.822142 0.138051 -0.004460 11.113900 0.062754 0.000000 12.522981 0.000000 2477.848305 -EDGE_SE2 67 220 0.783704 -1.176736 -1.412900 17.863537 -14.737201 0.000000 43.275118 0.000000 429.399329 -EDGE_SE2 81 220 -0.868391 -0.009825 -0.046880 11.522030 -7.053327 0.000000 132.179889 0.000000 2281.109865 -EDGE_SE2 81 226 2.836453 0.058719 0.049150 11.112174 0.037334 0.000000 12.422974 0.000000 2271.249469 -EDGE_SE2 87 226 -0.459640 0.184679 0.343830 185.785423 196.810927 0.000000 232.864045 0.000000 1384.367338 -EDGE_SE2 87 231 1.060624 0.863823 0.294010 34.429085 -29.740516 0.000000 94.681322 0.000000 4479.050905 -EDGE_SE2 94 231 -2.231597 0.316386 0.180250 23.930088 5.134954 0.000000 37.661225 0.000000 5384.101583 -EDGE_SE2 94 241 2.816677 0.483252 0.041400 22.259441 -0.288013 0.000000 24.450978 0.000000 6915.540303 -EDGE_SE2 101 241 -1.436886 0.314097 -0.098870 23.168499 8.096966 0.000000 91.505166 0.000000 6211.101543 -EDGE_SE2 101 247 2.168416 0.280309 -0.003870 22.564171 -2.567078 0.000000 41.493789 0.000000 7442.285250 -EDGE_SE2 107 247 -1.536762 0.375104 0.051050 26.954959 15.833327 0.000000 75.192472 0.000000 6789.136027 -EDGE_SE2 107 254 0.592787 -1.020976 -0.778000 30.649088 30.837091 0.000000 135.066803 0.000000 2372.453724 -EDGE_SE2 107 256 0.707309 -1.207974 -1.163740 23.417473 -9.695697 0.000000 100.872264 0.000000 1601.957964 -EDGE_SE2 107 258 0.976528 -2.202656 -1.227730 22.289493 -0.904508 0.000000 34.383996 0.000000 1511.249453 -EDGE_SE2 114 254 -0.931502 -0.024068 0.567580 77.556805 91.947180 0.000000 175.007037 0.000000 3052.121623 -EDGE_SE2 114 256 -0.723652 0.045801 0.181840 43.302820 84.297616 0.000000 359.313621 0.000000 5369.624220 -EDGE_SE2 114 258 0.306031 0.086093 0.117850 69.684517 -301.023297 0.000000 1931.422497 0.000000 6001.975262 -EDGE_SE2 121 266 0.737190 -0.017200 -0.118240 25.326151 -32.604829 0.000000 364.715589 0.000000 5997.789466 -EDGE_SE2 126 266 -1.480397 0.199141 0.062860 24.793867 12.913265 0.000000 87.064919 0.000000 6639.098888 -EDGE_SE2 126 272 2.350796 0.151313 0.025060 22.243466 -0.541415 0.000000 36.020406 0.000000 7137.772305 -EDGE_SE2 132 272 -1.375990 0.193564 -0.069560 22.622461 5.692420 0.000000 103.182984 0.000000 6556.181353 -EDGE_SE2 132 278 2.220707 0.319882 -0.000500 22.580601 -2.479176 0.000000 39.372548 0.000000 7492.505621 -EDGE_SE2 138 278 -1.378019 0.626427 0.016990 34.209796 25.223836 0.000000 75.297341 0.000000 7251.500784 -EDGE_SE2 138 284 2.391863 0.324204 -0.075755 22.750660 -2.473459 0.000000 33.799752 0.000000 6480.884307 -EDGE_SE2 151 284 -2.650853 -0.975732 1.454550 24.484817 1.146301 0.000000 22.802974 0.000000 1244.851357 -EDGE_SE2 151 291 -1.498500 0.364159 0.021790 26.317431 15.382872 0.000000 80.005044 0.000000 7183.530951 -EDGE_SE2 151 297 2.217429 -0.068852 -0.223460 22.895631 -3.456384 0.000000 39.962710 0.000000 5010.507463 -EDGE_SE2 19 305 -1.044094 0.006772 0.289080 17.951036 22.463977 0.000000 84.888274 0.000000 1504.458692 -EDGE_SE2 19 315 1.796874 2.231292 1.917670 11.894814 0.476141 0.000000 11.400392 0.000000 293.675468 -EDGE_SE2 19 337 1.676359 1.138847 2.369960 23.812750 -2.606854 0.000000 11.646135 0.000000 220.135719 -EDGE_SE2 19 342 2.451034 1.014379 -0.106190 11.820054 -1.302086 0.000000 13.502599 0.000000 2043.057325 -EDGE_SE2 19 1016 0.039741 0.374380 -2.852145 602.592071 -246.735273 0.000000 114.036309 0.000000 168.474698 -EDGE_SE2 25 315 -1.587705 2.017012 1.738340 12.043194 -1.708941 0.000000 14.244392 0.000000 333.399749 -EDGE_SE2 25 337 -1.901147 0.963583 2.190630 13.452340 -4.476777 0.000000 19.671370 0.000000 245.576678 -EDGE_SE2 25 342 -1.161097 0.702932 -0.285520 13.939899 10.682557 0.000000 51.452426 0.000000 1512.802847 -EDGE_SE2 25 367 0.878430 -0.159970 0.910020 100.995987 46.868336 0.000000 35.549493 0.000000 685.273881 -EDGE_SE2 25 374 2.840920 -0.557124 -0.601610 11.240233 -0.298749 0.000000 11.802326 0.000000 974.600130 -EDGE_SE2 25 1008 0.839778 0.868849 2.614245 65.217790 -13.300389 0.000000 14.380585 0.000000 191.383617 -EDGE_SE2 25 1010 0.208016 0.817490 -3.078070 128.288560 -37.883138 0.000000 23.358623 0.000000 150.324807 -EDGE_SE2 32 367 -1.650170 -1.061836 1.727680 23.555966 5.481395 0.000000 13.525417 0.000000 336.010748 -EDGE_SE2 32 374 -0.018221 0.098268 0.216050 10000.716890 -326.857444 0.000000 21.805806 0.000000 1690.585519 -EDGE_SE2 32 382 0.235335 2.451229 2.821510 16.224704 1.166981 0.000000 11.377430 0.000000 171.186695 -EDGE_SE2 32 387 0.993162 2.566664 0.274705 12.448992 -1.004261 0.000000 11.864945 0.000000 1538.582680 -EDGE_SE2 32 1003 0.362306 -0.196467 3.066965 108.121054 215.919400 0.000000 491.692649 0.000000 151.146840 -EDGE_SE2 32 1008 -2.427177 -0.386394 -2.851280 11.206045 0.712595 0.000000 16.460019 0.000000 168.550413 -EDGE_SE2 32 1010 -2.821790 -0.882420 -2.260410 11.209350 0.150567 0.000000 11.341881 0.000000 235.177395 -EDGE_SE2 44 437 0.696650 -2.771050 -0.205460 12.032017 0.446847 0.000000 11.327933 0.000000 1720.419675 -EDGE_SE2 44 454 -1.152851 -1.893499 1.516715 13.178717 3.850191 0.000000 18.280745 0.000000 394.704273 -EDGE_SE2 44 467 1.218289 1.232598 1.113140 13.331453 6.657638 0.000000 31.073862 0.000000 559.865191 -EDGE_SE2 44 494 2.154809 -0.649767 -0.306530 11.112721 -0.117867 0.000000 19.740180 0.000000 1464.539994 -EDGE_SE2 44 988 2.712903 -0.996652 3.047100 11.166944 0.211947 0.000000 11.915683 0.000000 152.634299 -EDGE_SE2 44 994 -0.892482 -0.642947 3.093485 38.865579 -34.860363 0.000000 54.896672 0.000000 149.194749 -EDGE_SE2 50 467 -2.756210 1.060141 1.334540 11.461044 -0.046083 0.000000 11.117180 0.000000 458.709115 -EDGE_SE2 50 494 -1.429190 -0.570621 -0.085130 17.367850 -12.471280 0.000000 35.969560 0.000000 2123.129418 -EDGE_SE2 50 500 2.268340 -0.490379 0.263640 12.680013 3.039151 0.000000 16.998309 0.000000 1565.644941 -EDGE_SE2 50 982 2.823043 -0.459737 -3.096925 11.157700 0.222838 0.000000 12.176961 0.000000 148.944310 -EDGE_SE2 50 988 -0.808543 -0.786485 -3.014685 35.481589 -32.415484 0.000000 54.227361 0.000000 155.108998 -EDGE_SE2 61 508 -1.449200 2.112314 1.477670 12.801726 -2.029955 0.000000 13.548517 0.000000 407.242490 -EDGE_SE2 61 522 -1.053664 -0.045704 0.099000 11.354883 4.375854 0.000000 89.660307 0.000000 2069.877405 -EDGE_SE2 61 528 2.466833 0.101003 -0.088240 11.198948 -0.676270 0.000000 16.317799 0.000000 2111.011691 -EDGE_SE2 61 976 1.165811 -0.076649 -3.054440 12.551016 9.349655 0.000000 71.820715 0.000000 152.082153 -EDGE_SE2 61 982 -2.503567 -0.322810 -2.934405 11.139618 0.360303 0.000000 15.665017 0.000000 161.503454 -EDGE_SE2 67 528 -1.085869 0.142906 -0.101590 11.172968 2.113193 0.000000 83.303853 0.000000 2060.155675 -EDGE_SE2 67 532 1.038480 -0.184540 -0.187270 11.121355 -0.898278 0.000000 89.877742 0.000000 1773.540133 -EDGE_SE2 67 556 0.875960 2.072499 -1.608750 12.194562 2.861649 0.000000 18.669404 0.000000 367.345805 -EDGE_SE2 67 564 0.934530 -0.521388 -1.425090 59.070878 -36.808963 0.000000 39.361868 0.000000 425.093327 -EDGE_SE2 67 567 1.078640 -1.127738 0.068640 28.794636 14.729412 0.000000 23.379907 0.000000 2189.158247 -EDGE_SE2 67 570 2.695842 -0.809094 0.129960 11.364179 0.564364 0.000000 12.369693 0.000000 1958.005326 -EDGE_SE2 67 965 0.918287 -0.079133 1.692110 113.199731 -21.468798 0.000000 15.625907 0.000000 344.948615 -EDGE_SE2 67 976 -2.389147 -0.017363 -3.067790 11.139434 0.425047 0.000000 17.489953 0.000000 151.085560 -EDGE_SE2 81 528 -2.540636 -1.571989 1.264430 11.150293 0.045554 0.000000 11.164073 0.000000 487.553422 -EDGE_SE2 81 532 -1.788049 0.441390 1.178750 29.071227 2.714944 0.000000 11.521516 0.000000 526.653783 -EDGE_SE2 81 564 -1.479377 0.271115 -0.059070 11.602730 4.003639 0.000000 43.715888 0.000000 2228.900474 -EDGE_SE2 81 567 -0.856391 0.288913 1.434660 118.478978 -20.563824 0.000000 15.049634 0.000000 421.758037 -EDGE_SE2 81 570 -0.839522 1.937122 1.495980 13.560960 -4.662733 0.000000 19.985567 0.000000 401.289509 -EDGE_SE2 81 575 -0.874481 2.499055 -2.998155 14.149112 0.594261 0.000000 11.227354 0.000000 156.394216 -EDGE_SE2 81 588 2.585410 -0.398590 0.032990 11.230814 0.636285 0.000000 14.493300 0.000000 2342.867749 -EDGE_SE2 81 959 1.715988 -0.147087 2.880085 11.804020 -3.896236 0.000000 33.019679 0.000000 166.057104 -EDGE_SE2 81 965 -1.915695 0.345142 3.058130 11.248005 1.439837 0.000000 26.255228 0.000000 151.805707 -EDGE_SE2 87 588 -0.567044 -0.325829 0.327670 19.376959 -42.100418 0.000000 225.541056 0.000000 1418.272639 -EDGE_SE2 87 597 1.033167 2.497995 1.747590 11.858143 1.168127 0.000000 12.937699 0.000000 331.158689 -EDGE_SE2 87 604 1.169979 2.733059 -1.279630 11.194520 0.099906 0.000000 11.230777 0.000000 481.073330 -EDGE_SE2 87 953 1.577352 0.448961 -2.823050 11.155436 1.074029 0.000000 37.135844 0.000000 171.048808 -EDGE_SE2 87 959 -1.472035 -0.337676 -3.108420 12.306884 -6.140766 0.000000 42.646361 0.000000 148.112032 -EDGE_SE2 94 597 -2.073375 1.943112 1.633830 11.708877 -0.635533 0.000000 11.786797 0.000000 360.383193 -EDGE_SE2 94 604 -1.910764 2.161126 -1.393390 11.355872 -0.402293 0.000000 11.772326 0.000000 436.428461 -EDGE_SE2 94 616 -0.567925 0.985809 1.728270 19.547380 -22.065015 0.000000 68.822033 0.000000 335.865437 -EDGE_SE2 94 632 -0.258230 -0.057031 -0.961010 1222.393668 -501.336231 0.000000 218.608540 0.000000 650.100338 -EDGE_SE2 94 637 2.180403 0.487495 0.048180 11.371804 -1.502621 0.000000 19.772123 0.000000 2275.455104 -EDGE_SE2 94 947 1.819562 0.355845 -2.812985 11.439117 2.406258 0.000000 28.763471 0.000000 171.952995 -EDGE_SE2 94 953 -1.765303 -0.154451 -2.936810 11.396122 2.414195 0.000000 31.560619 0.000000 161.306214 -EDGE_SE2 101 637 -2.066317 0.407256 -0.092090 11.230841 1.163903 0.000000 22.425529 0.000000 2096.153815 -EDGE_SE2 101 642 0.702540 0.058990 -0.158060 22.012272 -44.195550 0.000000 190.288971 0.000000 1864.137257 -EDGE_SE2 101 645 1.268565 0.117224 1.302975 55.348130 16.649223 0.000000 17.377280 0.000000 471.369465 -EDGE_SE2 101 657 0.970735 1.275733 -1.200065 31.327289 12.383774 0.000000 18.697009 0.000000 516.498549 -EDGE_SE2 101 663 2.721944 0.234701 0.154665 11.121870 0.156475 0.000000 13.386764 0.000000 1875.114422 -EDGE_SE2 101 665 2.743644 0.343689 1.484400 12.992900 0.403085 0.000000 11.197453 0.000000 405.039117 -EDGE_SE2 101 939 1.736598 0.040097 -3.139770 11.121070 -0.468281 0.000000 33.131371 0.000000 145.877255 -EDGE_SE2 101 944 -1.229619 0.290529 3.034680 11.913468 6.379852 0.000000 61.839764 0.000000 153.575457 -EDGE_SE2 101 947 -2.442020 0.327348 -2.953255 11.646767 1.607820 0.000000 15.937136 0.000000 159.966957 -EDGE_SE2 101 1138 -0.044980 -2.128090 1.406340 11.334711 -1.549412 0.000000 21.847605 0.000000 431.743719 -EDGE_SE2 101 1188 1.043367 -1.716987 3.078145 20.296004 6.412523 0.000000 15.588077 0.000000 150.319256 -EDGE_SE2 107 642 -2.988279 0.073654 -0.103140 11.111606 -0.006296 0.000000 11.191151 0.000000 2054.370375 -EDGE_SE2 107 645 -2.426303 0.162871 1.357895 16.787995 0.834037 0.000000 11.233646 0.000000 449.666954 -EDGE_SE2 107 663 -0.981564 0.359950 0.209585 33.867694 36.211234 0.000000 68.731953 0.000000 1708.704657 -EDGE_SE2 107 665 -0.965880 0.469964 1.539320 74.030616 -28.201297 0.000000 23.751280 0.000000 387.708339 -EDGE_SE2 107 680 -1.101202 1.597727 -1.082720 11.315853 -1.766538 0.000000 26.353031 0.000000 576.339299 -EDGE_SE2 107 683 -0.373238 0.237253 -0.978670 91.473664 -183.671027 0.000000 430.896755 0.000000 638.547590 -EDGE_SE2 107 704 -0.174419 -0.744617 -2.364960 56.805507 -72.228521 0.000000 125.281768 0.000000 220.790405 -EDGE_SE2 107 714 -0.001585 -1.518738 0.040750 43.298168 -1.345998 0.000000 11.167398 0.000000 2308.060399 -EDGE_SE2 107 730 1.719547 -1.998733 -2.849795 13.843772 1.215931 0.000000 11.652154 0.000000 168.680442 -EDGE_SE2 107 929 0.482300 -2.592003 1.960350 11.247596 0.654505 0.000000 14.249748 0.000000 285.268546 -EDGE_SE2 107 935 -0.294578 0.372182 2.191385 12.146819 -21.145445 0.000000 442.825321 0.000000 245.460450 -EDGE_SE2 107 939 -1.954743 0.111552 -3.084850 11.304032 1.688716 0.000000 25.893149 0.000000 149.826206 -EDGE_SE2 107 1147 -0.324254 -1.481983 0.140150 39.532534 -10.553850 0.000000 15.030118 0.000000 1923.162692 -EDGE_SE2 107 1150 0.364219 -1.279939 1.435915 18.388124 -16.646666 0.000000 49.191505 0.000000 421.323458 -EDGE_SE2 114 663 -2.629135 -1.250276 1.555165 11.663410 0.273309 0.000000 11.246360 0.000000 382.914669 -EDGE_SE2 114 665 -2.732868 -1.210420 2.884900 11.143210 -0.040214 0.000000 11.161493 0.000000 165.645759 -EDGE_SE2 114 683 -2.373686 -0.684712 0.366910 11.150086 0.451690 0.000000 16.345825 0.000000 1338.012489 -EDGE_SE2 114 704 -1.372213 -0.710183 -1.019380 41.720375 -2.264013 0.000000 11.278569 0.000000 613.061308 -EDGE_SE2 114 714 -0.579045 -0.714588 1.386330 35.416827 44.860054 0.000000 93.907456 0.000000 439.014644 -EDGE_SE2 114 730 0.273187 0.855886 -1.504215 26.282898 38.481991 0.000000 108.717525 0.000000 398.654506 -EDGE_SE2 114 929 0.575175 -0.482602 -2.977255 107.010292 82.154133 0.000000 81.490248 0.000000 158.042201 -EDGE_SE2 114 935 -2.487642 -0.577907 -2.746220 11.227888 0.692283 0.000000 15.215150 0.000000 178.136720 -EDGE_SE2 114 1147 -0.686929 -1.020901 1.485730 24.072771 23.324553 0.000000 53.083724 0.000000 404.605797 -EDGE_SE2 114 1150 -0.730123 -0.304695 2.781495 80.988104 -74.193686 0.000000 89.888157 0.000000 174.828760 -EDGE_SE2 114 1158 1.965070 -0.055808 0.083960 11.296704 1.644922 0.000000 25.690196 0.000000 2127.715200 -EDGE_SE2 114 1175 2.570804 -0.255481 2.913020 11.175699 -0.495876 0.000000 14.918247 0.000000 163.273564 -EDGE_SE2 121 754 -0.176774 -0.090674 -0.104160 764.277342 -1154.350823 0.000000 1780.343146 0.000000 2050.576559 -EDGE_SE2 121 759 2.795658 -0.372882 -0.047990 11.121537 0.122936 0.000000 12.560684 0.000000 2276.280256 -EDGE_SE2 121 923 -0.359940 -0.158411 2.816780 299.677751 -316.410365 0.000000 358.051835 0.000000 171.611249 -EDGE_SE2 121 1158 -1.765259 0.015433 0.094390 11.333442 2.148138 0.000000 31.866199 0.000000 2087.352405 -EDGE_SE2 121 1164 1.939145 -0.416391 -0.071910 11.388217 1.971985 0.000000 25.144479 0.000000 2175.822000 -EDGE_SE2 121 1175 -1.157476 -0.177912 2.923450 19.220682 -20.867733 0.000000 64.808438 0.000000 162.406633 -EDGE_SE2 126 754 -2.366181 -0.037747 0.076940 11.136170 0.410365 0.000000 17.831325 0.000000 2155.544499 -EDGE_SE2 126 759 0.608470 0.220030 0.133110 21.370901 -47.238010 0.000000 228.603826 0.000000 1947.134106 -EDGE_SE2 126 762 1.256487 0.430359 1.248090 39.878585 21.991658 0.000000 27.922912 0.000000 494.666638 -EDGE_SE2 126 923 -2.534151 -0.137367 2.997880 11.281716 -0.850942 0.000000 15.355440 0.000000 156.415757 -EDGE_SE2 126 1164 -0.226200 0.022965 0.109190 94.980319 392.781106 0.000000 1850.606209 0.000000 2032.020653 -EDGE_SE2 132 762 -2.439040 0.574751 1.153470 15.760986 0.874518 0.000000 11.275585 0.000000 539.091342 -EDGE_SE2 132 778 -1.013501 1.621706 1.561210 15.810999 -7.362314 0.000000 22.644082 0.000000 381.109374 -EDGE_SE2 132 792 -0.882133 1.768911 -1.797920 16.975203 -7.109142 0.000000 19.729650 0.000000 319.351840 -EDGE_SE2 132 800 1.214689 0.372313 0.005900 15.310892 -13.996183 0.000000 57.754774 0.000000 2470.759036 -EDGE_SE2 132 907 2.246094 -0.166035 -3.063890 11.307039 1.283425 0.000000 19.518199 0.000000 151.375685 -EDGE_SE2 132 911 0.287430 -0.091199 2.898905 15.641604 70.080974 0.000000 1095.174761 0.000000 164.457860 -EDGE_SE2 132 1084 -0.744736 -2.350749 -1.849821 11.115227 0.148119 0.000000 16.441489 0.000000 307.825761 -EDGE_SE2 138 800 -2.384799 0.661256 0.023390 11.548813 1.446295 0.000000 15.890090 0.000000 2387.028865 -EDGE_SE2 138 806 1.314158 0.976356 0.186155 16.125723 -10.306715 0.000000 32.294877 0.000000 1776.876918 -EDGE_SE2 138 821 1.339602 0.836157 -1.728640 27.615689 14.355051 0.000000 23.596586 0.000000 335.774357 -EDGE_SE2 138 823 1.391787 0.830084 -0.201680 23.357993 -13.427129 0.000000 25.832230 0.000000 1731.260189 -EDGE_SE2 138 903 0.257877 0.385262 2.468460 462.130945 37.644489 0.000000 14.253118 0.000000 207.810089 -EDGE_SE2 138 904 0.211460 0.361905 2.918540 518.619452 -160.188745 0.000000 61.672712 0.000000 162.813885 -EDGE_SE2 138 907 -1.344137 0.141028 -3.046400 12.828819 8.485440 0.000000 53.029004 0.000000 152.687113 -EDGE_SE2 151 828 -2.783661 1.064375 1.529770 11.244135 -0.044701 0.000000 11.126133 0.000000 390.641099 -EDGE_SE2 151 847 -2.892269 0.357584 -1.720550 11.773808 0.017727 0.000000 11.111585 0.000000 337.774286 -EDGE_SE2 151 855 0.421564 -0.036975 -0.072980 11.226261 7.937694 0.000000 558.283669 0.000000 2171.484605 -EDGE_SE2 151 895 -0.308314 0.072387 -2.940720 183.554391 374.539119 0.000000 824.593387 0.000000 160.986275 -EDGE_SE2 151 897 -0.653297 -0.340780 -2.145820 53.093226 74.186112 0.000000 142.204535 0.000000 252.622641 -EDGE_SE2 151 1029 2.658346 -1.322835 -1.612160 11.303644 -0.086066 0.000000 11.149585 0.000000 366.387340 -EDGE_SE2 157 297 -1.431635 -0.047784 -0.192100 12.991577 -8.198575 0.000000 46.855781 0.000000 1759.197636 -EDGE_SE2 157 305 2.323872 -0.569035 0.026110 11.551318 1.614103 0.000000 17.029536 0.000000 2374.390623 -EDGE_SE2 157 1029 -0.951615 -1.287326 -1.580800 20.706819 13.256279 0.000000 29.424395 0.000000 375.345582 -EDGE_SE2 157 1217 -0.999593 -2.295582 1.588120 11.945029 1.827929 0.000000 15.117890 0.000000 373.225399 -EDGE_SE2 163 297 -0.152489 -1.643361 1.294160 11.969142 -4.607638 0.000000 35.854192 0.000000 474.998898 -EDGE_SE2 163 305 0.683999 2.054722 1.512370 11.800954 2.562970 0.000000 20.633308 0.000000 396.070787 -EDGE_SE2 163 1029 1.123157 -1.269718 -0.094540 22.165118 11.817460 0.000000 23.744753 0.000000 2086.780326 -EDGE_SE2 163 1217 2.123761 -1.402656 3.074380 12.166102 1.857716 0.000000 14.382333 0.000000 150.597217 -EDGE_SE2 166 297 -2.448623 -0.097923 -0.181930 11.379485 -1.189522 0.000000 16.383459 0.000000 1789.602165 -EDGE_SE2 166 305 1.311990 -0.580954 0.036280 18.290583 14.744491 0.000000 41.391889 0.000000 2328.015008 -EDGE_SE2 166 1016 2.453320 -0.496114 -3.104945 11.376696 1.103524 0.000000 15.696336 0.000000 148.362881 -EDGE_SE2 166 1029 -1.956023 -1.332520 -1.570630 15.716267 3.136091 0.000000 13.246776 0.000000 378.321363 -EDGE_SE2 172 305 -2.223813 -0.584373 0.139610 11.218103 -0.907468 0.000000 18.807912 0.000000 1924.985691 -EDGE_SE2 172 315 0.916741 1.192284 1.768200 29.887371 16.398688 0.000000 25.433291 0.000000 326.245913 -EDGE_SE2 172 328 0.389353 2.701274 -1.418880 11.306838 0.643966 0.000000 13.229838 0.000000 427.278816 -EDGE_SE2 172 337 0.634889 0.129966 2.220490 195.557030 -88.592401 0.000000 53.663494 0.000000 241.043874 -EDGE_SE2 172 342 1.382392 -0.108475 -0.255660 12.384043 -7.102031 0.000000 50.735268 0.000000 1585.608223 -EDGE_SE2 172 1010 2.747473 0.046909 -3.048210 11.123505 0.162102 0.000000 13.231218 0.000000 152.550608 -EDGE_SE2 172 1016 -1.097321 -0.382262 -3.001615 13.480215 -11.980076 0.000000 71.691915 0.000000 156.123881 -EDGE_SE2 178 342 -2.376956 -0.213431 -0.183040 11.578392 -1.671546 0.000000 17.090523 0.000000 1786.245513 -EDGE_SE2 178 367 -0.259854 -0.863160 1.012500 18.840526 -28.383170 0.000000 115.336891 0.000000 617.260137 -EDGE_SE2 178 374 1.732968 -1.057467 -0.499130 11.142356 0.640290 0.000000 24.232266 0.000000 1112.401122 -EDGE_SE2 178 1003 1.826983 -1.529516 2.351785 11.166956 -0.600028 0.000000 17.558198 0.000000 222.529516 -EDGE_SE2 178 1008 -0.403552 0.156306 2.716725 12.710306 -28.871300 0.000000 532.343545 0.000000 180.975206 -EDGE_SE2 178 1010 -1.026746 0.040588 -2.975590 14.592518 16.700937 0.000000 91.228510 0.000000 158.174631 -EDGE_SE2 183 367 -1.618063 -1.419954 1.686080 18.191945 4.896376 0.000000 14.496941 0.000000 346.499109 -EDGE_SE2 183 374 0.060720 -0.328723 0.174450 894.828841 7.251305 0.000000 11.170611 0.000000 1812.470490 -EDGE_SE2 183 382 0.411911 2.011657 2.779910 23.397894 1.979206 0.000000 11.429930 0.000000 174.975438 -EDGE_SE2 183 387 1.173883 2.095476 0.233105 14.481439 -3.100632 0.000000 13.963629 0.000000 1644.144968 -EDGE_SE2 183 1003 0.428660 -0.639029 3.025365 102.305125 77.922908 0.000000 77.694205 0.000000 154.287027 -EDGE_SE2 183 1008 -2.366308 -0.712782 -2.892880 11.121230 -0.230529 0.000000 16.363269 0.000000 164.967341 -EDGE_SE2 189 400 -1.948699 2.200613 -1.116370 11.144116 -0.119102 0.000000 11.540899 0.000000 558.157565 -EDGE_SE2 189 414 -0.254807 -1.783532 -1.508360 11.922188 3.913799 0.000000 29.996898 0.000000 397.338159 -EDGE_SE2 189 454 0.831360 -1.515476 1.318995 21.578630 -11.156350 0.000000 23.001623 0.000000 464.879365 -EDGE_SE2 189 994 1.332308 -0.340434 2.895765 11.111898 0.181350 0.000000 52.882967 0.000000 164.723074 -EDGE_SE2 195 437 -0.591701 -2.641206 -0.200180 13.648824 -0.051289 0.000000 11.112148 0.000000 1735.590395 -EDGE_SE2 195 467 -0.091210 1.365140 1.118420 21.523802 -18.224556 0.000000 43.008191 0.000000 557.077827 -EDGE_SE2 195 484 0.655807 2.573505 -2.009240 11.219291 -0.565783 0.000000 14.070164 0.000000 276.074540 -EDGE_SE2 195 494 0.855236 -0.512254 -0.301250 16.102937 20.540136 0.000000 95.628725 0.000000 1476.449250 -EDGE_SE2 195 988 1.415155 -0.856188 3.052380 16.022409 10.041613 0.000000 31.642140 0.000000 152.236812 -EDGE_SE2 195 994 -2.192048 -0.521524 3.098765 11.750475 -2.253964 0.000000 19.057069 0.000000 148.810613 -EDGE_SE2 201 494 -2.683977 -0.793909 -0.034430 11.276756 -0.496479 0.000000 12.599187 0.000000 2336.349413 -EDGE_SE2 201 500 1.004735 -0.526385 0.314340 45.186413 33.298498 0.000000 43.650514 0.000000 1447.186686 -EDGE_SE2 201 982 1.557172 -0.467671 -3.046225 14.919173 9.340266 0.000000 34.020554 0.000000 152.700298 -EDGE_SE2 201 988 -2.053188 -0.978041 -2.963985 11.683303 -2.092334 0.000000 18.762142 0.000000 159.102109 -EDGE_SE2 203 500 -0.236863 -0.548090 0.348290 153.663942 -134.464803 0.000000 137.946777 0.000000 1375.223806 -EDGE_SE2 203 508 1.553867 1.875066 1.399800 12.536000 2.482853 0.000000 15.437455 0.000000 434.100125 -EDGE_SE2 203 522 1.780329 -0.307182 0.021130 11.822071 3.657498 0.000000 29.926926 0.000000 2397.606666 -EDGE_SE2 203 982 0.313263 -0.470658 -3.012275 253.866414 119.649456 0.000000 70.084044 0.000000 155.295388 -EDGE_SE2 209 508 -2.161765 2.058644 1.468780 11.180293 -0.053576 0.000000 11.152602 0.000000 410.180706 -EDGE_SE2 209 522 -1.785428 -0.102806 0.090110 11.132515 0.656456 0.000000 31.244975 0.000000 2103.775347 -EDGE_SE2 209 528 1.736233 0.012599 -0.097130 11.350617 -2.286079 0.000000 32.931671 0.000000 2076.939411 -EDGE_SE2 209 976 0.433683 -0.153481 -3.063330 87.280240 171.295909 0.000000 396.336584 0.000000 151.417412 -EDGE_SE2 220 528 -1.597199 -1.638814 1.311310 13.034804 3.414597 0.000000 17.172093 0.000000 467.976033 -EDGE_SE2 220 532 -0.939792 0.407621 1.225630 94.950637 -5.379789 0.000000 11.456320 0.000000 504.700895 -EDGE_SE2 220 564 -0.623480 0.251998 -0.012190 38.845567 71.101745 0.000000 193.391889 0.000000 2440.146629 -EDGE_SE2 220 567 -0.002013 0.298972 1.481540 21.284937 -105.664807 0.000000 1108.540123 0.000000 405.973278 -EDGE_SE2 220 570 -0.062402 1.946160 1.542860 11.165977 -0.913492 0.000000 26.320380 0.000000 386.629607 -EDGE_SE2 220 575 -0.123656 2.505837 -2.951275 15.792523 -0.664538 0.000000 11.205444 0.000000 160.127317 -EDGE_SE2 220 959 2.587973 -0.016000 2.926965 11.274656 -0.773198 0.000000 14.766597 0.000000 162.116000 -EDGE_SE2 220 965 -1.062787 0.305497 3.105010 15.212918 16.523642 0.000000 77.674651 0.000000 148.358205 -EDGE_SE2 226 231 1.660221 0.126920 -0.049820 11.505996 -3.114430 0.000000 35.674411 0.000000 2268.351350 -EDGE_SE2 226 588 -0.273207 -0.444423 -0.016160 274.806053 -156.291042 0.000000 103.744249 0.000000 2421.117227 -EDGE_SE2 226 597 2.185242 1.674700 1.403760 12.078039 1.038206 0.000000 12.225850 0.000000 432.671013 -EDGE_SE2 226 953 2.006857 -0.437847 3.116305 11.557944 2.329386 0.000000 23.254435 0.000000 147.545120 -EDGE_SE2 226 959 -1.129223 -0.150509 2.830935 23.235807 -25.544568 0.000000 64.928953 0.000000 170.345385 -EDGE_SE2 923 1175 0.749610 0.273000 0.106670 19.536607 -34.047517 0.000000 148.697481 0.000000 2041.285424 -EDGE_SE2 929 1175 -2.005899 0.102421 -0.392910 12.648561 -4.320259 0.000000 23.251108 0.000000 1288.528106 -EDGE_SE2 939 1188 0.696432 1.755817 -0.065270 26.430265 -4.946684 0.000000 12.708437 0.000000 2203.031036 -EDGE_SE2 1029 1217 1.008685 -0.037889 -3.114265 11.476877 5.630362 0.000000 97.781127 0.000000 147.691473 -EDGE_SE2 1044 1217 2.098504 -0.838430 0.479890 15.976239 4.188481 0.000000 14.717054 0.000000 1141.513725 -EDGE_SE2 1050 1210 -0.300235 -2.565672 1.536560 11.137270 0.317303 0.000000 14.960021 0.000000 388.552520 -EDGE_SE2 1050 1217 0.231465 1.668290 1.559140 11.493589 3.014437 0.000000 34.868922 0.000000 381.726156 -EDGE_SE2 1056 1217 2.128743 -0.472375 -0.931160 15.353750 -4.908186 0.000000 16.789250 0.000000 670.352902 -EDGE_SE2 1061 1210 1.269232 -1.441319 -2.909610 23.568115 6.644624 0.000000 14.655385 0.000000 163.558506 -EDGE_SE2 1075 1210 -1.662329 0.436026 -1.599840 32.701727 -4.997844 0.000000 12.268023 0.000000 369.868006 -EDGE_SE2 1084 1210 2.070374 1.896269 1.836205 12.355692 0.641825 0.000000 11.442098 0.000000 310.788312 -EDGE_SE2 1088 1210 0.609503 -1.485166 0.536770 38.204841 -4.021013 0.000000 11.707874 0.000000 1058.576530 -EDGE_SE2 1093 1210 -0.233452 -0.529583 1.494360 42.853783 90.090527 0.000000 266.801722 0.000000 401.810926 -EDGE_SE2 1098 1210 -0.378280 -0.172442 -2.937025 38.903093 -122.470929 0.000000 550.803768 0.000000 161.288572 -EDGE_SE2 1138 1188 0.583736 -1.006358 1.671805 21.764394 -23.563240 0.000000 63.228969 0.000000 350.211491 -EDGE_SE2 1147 1188 -2.232188 0.113982 2.992915 11.195782 -0.864255 0.000000 19.932721 0.000000 156.804966 -EDGE_SE2 1150 1188 -0.789302 2.834301 1.697150 11.120354 -0.063189 0.000000 11.543094 0.000000 343.660651 -EDGE_SE2 1158 1175 0.586855 -0.249767 2.829060 13.000858 20.975969 0.000000 243.941877 0.000000 170.512281 diff --git a/SLAM/GraphBasedSLAM/graph_based_slam.py b/SLAM/GraphBasedSLAM/graph_based_slam.py deleted file mode 100644 index edd20a959c2..00000000000 --- a/SLAM/GraphBasedSLAM/graph_based_slam.py +++ /dev/null @@ -1,322 +0,0 @@ -""" - -Graph based SLAM example - -author: Atsushi Sakai (@Atsushi_twi) - -Ref - -[A Tutorial on Graph-Based SLAM] -(http://www2.informatik.uni-freiburg.de/~stachnis/pdf/grisetti10titsmag.pdf) - -""" -import sys -import pathlib -sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) - -import copy -import itertools -import math - -import matplotlib.pyplot as plt -import numpy as np -from scipy.spatial.transform import Rotation as Rot -from utils.angle import angle_mod - -# Simulation parameter -Q_sim = np.diag([0.2, np.deg2rad(1.0)]) ** 2 -R_sim = np.diag([0.1, np.deg2rad(10.0)]) ** 2 - -DT = 2.0 # time tick [s] -SIM_TIME = 100.0 # simulation time [s] -MAX_RANGE = 30.0 # maximum observation range -STATE_SIZE = 3 # State size [x,y,yaw] - -# Covariance parameter of Graph Based SLAM -C_SIGMA1 = 0.1 -C_SIGMA2 = 0.1 -C_SIGMA3 = np.deg2rad(1.0) - -MAX_ITR = 20 # Maximum iteration - -show_graph_d_time = 20.0 # [s] -show_animation = True - - -class Edge: - - def __init__(self): - self.e = np.zeros((3, 1)) - self.omega = np.zeros((3, 3)) # information matrix - self.d1 = 0.0 - self.d2 = 0.0 - self.yaw1 = 0.0 - self.yaw2 = 0.0 - self.angle1 = 0.0 - self.angle2 = 0.0 - self.id1 = 0 - self.id2 = 0 - - -def cal_observation_sigma(): - sigma = np.zeros((3, 3)) - sigma[0, 0] = C_SIGMA1 ** 2 - sigma[1, 1] = C_SIGMA2 ** 2 - sigma[2, 2] = C_SIGMA3 ** 2 - - return sigma - - -def calc_3d_rotational_matrix(angle): - return Rot.from_euler('z', angle).as_matrix() - - -def calc_edge(x1, y1, yaw1, x2, y2, yaw2, d1, - angle1, d2, angle2, t1, t2): - edge = Edge() - - tangle1 = pi_2_pi(yaw1 + angle1) - tangle2 = pi_2_pi(yaw2 + angle2) - tmp1 = d1 * math.cos(tangle1) - tmp2 = d2 * math.cos(tangle2) - tmp3 = d1 * math.sin(tangle1) - tmp4 = d2 * math.sin(tangle2) - - edge.e[0, 0] = x2 - x1 - tmp1 + tmp2 - edge.e[1, 0] = y2 - y1 - tmp3 + tmp4 - edge.e[2, 0] = 0 - - Rt1 = calc_3d_rotational_matrix(tangle1) - Rt2 = calc_3d_rotational_matrix(tangle2) - - sig1 = cal_observation_sigma() - sig2 = cal_observation_sigma() - - edge.omega = np.linalg.inv(Rt1 @ sig1 @ Rt1.T + Rt2 @ sig2 @ Rt2.T) - - edge.d1, edge.d2 = d1, d2 - edge.yaw1, edge.yaw2 = yaw1, yaw2 - edge.angle1, edge.angle2 = angle1, angle2 - edge.id1, edge.id2 = t1, t2 - - return edge - - -def calc_edges(x_list, z_list): - edges = [] - cost = 0.0 - z_ids = list(itertools.combinations(range(len(z_list)), 2)) - - for (t1, t2) in z_ids: - x1, y1, yaw1 = x_list[0, t1], x_list[1, t1], x_list[2, t1] - x2, y2, yaw2 = x_list[0, t2], x_list[1, t2], x_list[2, t2] - - if z_list[t1] is None or z_list[t2] is None: - continue # No observation - - for iz1 in range(len(z_list[t1][:, 0])): - for iz2 in range(len(z_list[t2][:, 0])): - if z_list[t1][iz1, 3] == z_list[t2][iz2, 3]: - d1 = z_list[t1][iz1, 0] - angle1, _ = z_list[t1][iz1, 1], z_list[t1][iz1, 2] - d2 = z_list[t2][iz2, 0] - angle2, _ = z_list[t2][iz2, 1], z_list[t2][iz2, 2] - - edge = calc_edge(x1, y1, yaw1, x2, y2, yaw2, d1, - angle1, d2, angle2, t1, t2) - - edges.append(edge) - cost += (edge.e.T @ edge.omega @ edge.e)[0, 0] - - print("cost:", cost, ",n_edge:", len(edges)) - return edges - - -def calc_jacobian(edge): - t1 = edge.yaw1 + edge.angle1 - A = np.array([[-1.0, 0, edge.d1 * math.sin(t1)], - [0, -1.0, -edge.d1 * math.cos(t1)], - [0, 0, 0]]) - - t2 = edge.yaw2 + edge.angle2 - B = np.array([[1.0, 0, -edge.d2 * math.sin(t2)], - [0, 1.0, edge.d2 * math.cos(t2)], - [0, 0, 0]]) - - return A, B - - -def fill_H_and_b(H, b, edge): - A, B = calc_jacobian(edge) - - id1 = edge.id1 * STATE_SIZE - id2 = edge.id2 * STATE_SIZE - - H[id1:id1 + STATE_SIZE, id1:id1 + STATE_SIZE] += A.T @ edge.omega @ A - H[id1:id1 + STATE_SIZE, id2:id2 + STATE_SIZE] += A.T @ edge.omega @ B - H[id2:id2 + STATE_SIZE, id1:id1 + STATE_SIZE] += B.T @ edge.omega @ A - H[id2:id2 + STATE_SIZE, id2:id2 + STATE_SIZE] += B.T @ edge.omega @ B - - b[id1:id1 + STATE_SIZE] += (A.T @ edge.omega @ edge.e) - b[id2:id2 + STATE_SIZE] += (B.T @ edge.omega @ edge.e) - - return H, b - - -def graph_based_slam(x_init, hz): - print("start graph based slam") - - z_list = copy.deepcopy(hz) - - x_opt = copy.deepcopy(x_init) - nt = x_opt.shape[1] - n = nt * STATE_SIZE - - for itr in range(MAX_ITR): - edges = calc_edges(x_opt, z_list) - - H = np.zeros((n, n)) - b = np.zeros((n, 1)) - - for edge in edges: - H, b = fill_H_and_b(H, b, edge) - - # to fix origin - H[0:STATE_SIZE, 0:STATE_SIZE] += np.identity(STATE_SIZE) - - dx = - np.linalg.inv(H) @ b - - for i in range(nt): - x_opt[0:3, i] += dx[i * 3:i * 3 + 3, 0] - - diff = (dx.T @ dx)[0, 0] - print("iteration: %d, diff: %f" % (itr + 1, diff)) - if diff < 1.0e-5: - break - - return x_opt - - -def calc_input(): - v = 1.0 # [m/s] - yaw_rate = 0.1 # [rad/s] - u = np.array([[v, yaw_rate]]).T - return u - - -def observation(xTrue, xd, u, RFID): - xTrue = motion_model(xTrue, u) - - # add noise to gps x-y - z = np.zeros((0, 4)) - - for i in range(len(RFID[:, 0])): - - dx = RFID[i, 0] - xTrue[0, 0] - dy = RFID[i, 1] - xTrue[1, 0] - d = math.hypot(dx, dy) - angle = pi_2_pi(math.atan2(dy, dx)) - xTrue[2, 0] - phi = pi_2_pi(math.atan2(dy, dx)) - if d <= MAX_RANGE: - dn = d + np.random.randn() * Q_sim[0, 0] # add noise - angle_noise = np.random.randn() * Q_sim[1, 1] - angle += angle_noise - phi += angle_noise - zi = np.array([dn, angle, phi, i]) - z = np.vstack((z, zi)) - - # add noise to input - ud1 = u[0, 0] + np.random.randn() * R_sim[0, 0] - ud2 = u[1, 0] + np.random.randn() * R_sim[1, 1] - ud = np.array([[ud1, ud2]]).T - - xd = motion_model(xd, ud) - - return xTrue, z, xd, ud - - -def motion_model(x, u): - F = np.array([[1.0, 0, 0], - [0, 1.0, 0], - [0, 0, 1.0]]) - - B = np.array([[DT * math.cos(x[2, 0]), 0], - [DT * math.sin(x[2, 0]), 0], - [0.0, DT]]) - - x = F @ x + B @ u - - return x - - -def pi_2_pi(angle): - return angle_mod(angle) - - -def main(): - print(__file__ + " start!!") - - time = 0.0 - - # RFID positions [x, y, yaw] - RFID = np.array([[10.0, -2.0, 0.0], - [15.0, 10.0, 0.0], - [3.0, 15.0, 0.0], - [-5.0, 20.0, 0.0], - [-5.0, 5.0, 0.0] - ]) - - # State Vector [x y yaw v]' - xTrue = np.zeros((STATE_SIZE, 1)) - xDR = np.zeros((STATE_SIZE, 1)) # Dead reckoning - - # history - hxTrue = [] - hxDR = [] - hz = [] - d_time = 0.0 - init = False - while SIM_TIME >= time: - - if not init: - hxTrue = xTrue - hxDR = xTrue - init = True - else: - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - - time += DT - d_time += DT - u = calc_input() - - xTrue, z, xDR, ud = observation(xTrue, xDR, u, RFID) - - hz.append(z) - - if d_time >= show_graph_d_time: - x_opt = graph_based_slam(hxDR, hz) - d_time = 0.0 - - if show_animation: # pragma: no cover - plt.cla() - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - plt.plot(RFID[:, 0], RFID[:, 1], "*k") - - plt.plot(hxTrue[0, :].flatten(), - hxTrue[1, :].flatten(), "-b") - plt.plot(hxDR[0, :].flatten(), - hxDR[1, :].flatten(), "-k") - plt.plot(x_opt[0, :].flatten(), - x_opt[1, :].flatten(), "-r") - plt.axis("equal") - plt.grid(True) - plt.title("Time" + str(time)[0:5]) - plt.pause(1.0) - - -if __name__ == '__main__': - main() diff --git a/SLAM/GraphBasedSLAM/graphslam/__init__.py b/SLAM/GraphBasedSLAM/graphslam/__init__.py deleted file mode 100644 index 6aa2872e77f..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -"""Graph SLAM solver in Python. - -""" diff --git a/SLAM/GraphBasedSLAM/graphslam/edge/__init__.py b/SLAM/GraphBasedSLAM/graphslam/edge/__init__.py deleted file mode 100644 index afb85490871..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/edge/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam diff --git a/SLAM/GraphBasedSLAM/graphslam/edge/edge_odometry.py b/SLAM/GraphBasedSLAM/graphslam/edge/edge_odometry.py deleted file mode 100644 index b247b97b437..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/edge/edge_odometry.py +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -r"""A class for odometry edges. - -""" - - -import numpy as np -import matplotlib.pyplot as plt - - -#: The difference that will be used for numerical differentiation -EPSILON = 1e-6 - - -class EdgeOdometry: - r"""A class for representing odometry edges in Graph SLAM. - - Parameters - ---------- - vertices : list[graphslam.vertex.Vertex] - A list of the vertices constrained by the edge - information : np.ndarray - The information matrix :math:`\Omega_j` associated with the edge - estimate : graphslam.pose.se2.PoseSE2 - The expected measurement :math:`\mathbf{z}_j` - - Attributes - ---------- - vertices : list[graphslam.vertex.Vertex] - A list of the vertices constrained by the edge - information : np.ndarray - The information matrix :math:`\Omega_j` associated with the edge - estimate : PoseSE2 - The expected measurement :math:`\mathbf{z}_j` - - """ - def __init__(self, vertex_ids, information, estimate, vertices=None): - self.vertex_ids = vertex_ids - self.information = information - self.estimate = estimate - self.vertices = vertices - - def calc_error(self): - r"""Calculate the error for the edge: :math:`\mathbf{e}_j \in \mathbb{R}^\bullet`. - - .. math:: - - \mathbf{e}_j = \mathbf{z}_j - (p_2 \ominus p_1) - - - Returns - ------- - np.ndarray - The error for the edge - - """ - return (self.estimate - (self.vertices[1].pose - self.vertices[0].pose)).to_compact() - - def calc_chi2(self): - r"""Calculate the :math:`\chi^2` error for the edge. - - .. math:: - - \mathbf{e}_j^T \Omega_j \mathbf{e}_j - - - Returns - ------- - float - The :math:`\chi^2` error for the edge - - """ - err = self.calc_error() - - return np.dot(np.dot(np.transpose(err), self.information), err) - - def calc_chi2_gradient_hessian(self): - r"""Calculate the edge's contributions to the graph's :math:`\chi^2` error, gradient (:math:`\mathbf{b}`), and Hessian (:math:`H`). - - Returns - ------- - float - The :math:`\chi^2` error for the edge - dict - The edge's contribution(s) to the gradient - dict - The edge's contribution(s) to the Hessian - - """ - chi2 = self.calc_chi2() - - err = self.calc_error() - - jacobians = self.calc_jacobians() - - return chi2, {v.index: np.dot(np.dot(np.transpose(err), self.information), jacobian) for v, jacobian in zip(self.vertices, jacobians)}, {(self.vertices[i].index, self.vertices[j].index): np.dot(np.dot(np.transpose(jacobians[i]), self.information), jacobians[j]) for i in range(len(jacobians)) for j in range(i, len(jacobians))} - - def calc_jacobians(self): - r"""Calculate the Jacobian of the edge's error with respect to each constrained pose. - - .. math:: - - \frac{\partial}{\partial \Delta \mathbf{x}^k} \left[ \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k) \right] - - - Returns - ------- - list[np.ndarray] - The Jacobian matrices for the edge with respect to each constrained pose - - """ - err = self.calc_error() - - # The dimensionality of the compact pose representation - dim = len(self.vertices[0].pose.to_compact()) - - return [self._calc_jacobian(err, dim, i) for i in range(len(self.vertices))] - - def _calc_jacobian(self, err, dim, vertex_index): - r"""Calculate the Jacobian of the edge with respect to the specified vertex's pose. - - Parameters - ---------- - err : np.ndarray - The current error for the edge (see :meth:`EdgeOdometry.calc_error`) - dim : int - The dimensionality of the compact pose representation - vertex_index : int - The index of the vertex (pose) for which we are computing the Jacobian - - Returns - ------- - np.ndarray - The Jacobian of the edge with respect to the specified vertex's pose - - """ - jacobian = np.zeros(err.shape + (dim,)) - p0 = self.vertices[vertex_index].pose.copy() - - for d in range(dim): - # update the pose - delta_pose = np.zeros(dim) - delta_pose[d] = EPSILON - self.vertices[vertex_index].pose += delta_pose - - # compute the numerical derivative - jacobian[:, d] = (self.calc_error() - err) / EPSILON - - # restore the pose - self.vertices[vertex_index].pose = p0.copy() - - return jacobian - - def to_g2o(self): - """Export the edge to the .g2o format. - - Returns - ------- - str - The edge in .g2o format - - """ - return "EDGE_SE2 {} {} {} {} {} ".format(self.vertex_ids[0], self.vertex_ids[1], self.estimate[0], self.estimate[1], self.estimate[2]) + " ".join([str(x) for x in self.information[np.triu_indices(3, 0)]]) + "\n" - - def plot(self, color='b'): - """Plot the edge. - - Parameters - ---------- - color : str - The color that will be used to plot the edge - - """ - xy = np.array([v.pose.position for v in self.vertices]) - plt.plot(xy[:, 0], xy[:, 1], color=color) diff --git a/SLAM/GraphBasedSLAM/graphslam/graph.py b/SLAM/GraphBasedSLAM/graphslam/graph.py deleted file mode 100644 index 672f63d60e2..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/graph.py +++ /dev/null @@ -1,282 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -r"""A ``Graph`` class that stores the edges and vertices required for Graph SLAM. - -""" - -import warnings -from collections import defaultdict -from functools import reduce - -import matplotlib.pyplot as plt -import numpy as np -from scipy.sparse import SparseEfficiencyWarning, lil_matrix -from scipy.sparse.linalg import spsolve - -warnings.simplefilter("ignore", SparseEfficiencyWarning) -warnings.filterwarnings("ignore", category=SparseEfficiencyWarning) - - -# pylint: disable=too-few-public-methods -class _Chi2GradientHessian: - r"""A class that is used to aggregate the :math:`\chi^2` error, gradient, and Hessian. - - Parameters - ---------- - dim : int - The compact dimensionality of the poses - - Attributes - ---------- - chi2 : float - The :math:`\chi^2` error - dim : int - The compact dimensionality of the poses - gradient : defaultdict - The contributions to the gradient vector - hessian : defaultdict - The contributions to the Hessian matrix - - """ - - def __init__(self, dim): - self.chi2 = 0. - self.dim = dim - self.gradient = defaultdict(lambda: np.zeros(dim)) - self.hessian = defaultdict(lambda: np.zeros((dim, dim))) - - @staticmethod - def update(chi2_grad_hess, incoming): - r"""Update the :math:`\chi^2` error and the gradient and Hessian dictionaries. - - Parameters - ---------- - chi2_grad_hess : _Chi2GradientHessian - The ``_Chi2GradientHessian`` that will be updated - incoming : tuple - - """ - chi2_grad_hess.chi2 += incoming[0] - - for idx, contrib in incoming[1].items(): - chi2_grad_hess.gradient[idx] += contrib - - for (idx1, idx2), contrib in incoming[2].items(): - if idx1 <= idx2: - chi2_grad_hess.hessian[idx1, idx2] += contrib - else: - chi2_grad_hess.hessian[idx2, idx1] += np.transpose(contrib) - - return chi2_grad_hess - - -class Graph(object): - r"""A graph that will be optimized via Graph SLAM. - - Parameters - ---------- - edges : list[graphslam.edge.edge_odometry.EdgeOdometry] - A list of the vertices in the graph - vertices : list[graphslam.vertex.Vertex] - A list of the vertices in the graph - - Attributes - ---------- - _chi2 : float, None - The current :math:`\chi^2` error, or ``None`` if it has not yet been computed - _edges : list[graphslam.edge.edge_odometry.EdgeOdometry] - A list of the edges (i.e., constraints) in the graph - _gradient : numpy.ndarray, None - The gradient :math:`\mathbf{b}` of the :math:`\chi^2` error, or ``None`` if it has not yet been computed - _hessian : scipy.sparse.lil_matrix, None - The Hessian matrix :math:`H`, or ``None`` if it has not yet been computed - _vertices : list[graphslam.vertex.Vertex] - A list of the vertices in the graph - - """ - - def __init__(self, edges, vertices): - # The vertices and edges lists - self._edges = edges - self._vertices = vertices - - # The chi^2 error, gradient, and Hessian - self._chi2 = None - self._gradient = None - self._hessian = None - - self._link_edges() - - def _link_edges(self): - """Fill in the ``vertices`` attributes for the graph's edges. - - """ - index_id_dict = {i: v.id for i, v in enumerate(self._vertices)} - id_index_dict = {v_id: v_index for v_index, v_id in - index_id_dict.items()} - - # Fill in the vertices' `index` attribute - for v in self._vertices: - v.index = id_index_dict[v.id] - - for e in self._edges: - e.vertices = [self._vertices[id_index_dict[v_id]] for v_id in - e.vertex_ids] - - def calc_chi2(self): - r"""Calculate the :math:`\chi^2` error for the ``Graph``. - - Returns - ------- - float - The :math:`\chi^2` error - - """ - self._chi2 = sum((e.calc_chi2() for e in self._edges)) - return self._chi2 - - def _calc_chi2_gradient_hessian(self): - r"""Calculate the :math:`\chi^2` error, the gradient :math:`\mathbf{b}`, and the Hessian :math:`H`. - - """ - n = len(self._vertices) - dim = len(self._vertices[0].pose.to_compact()) - chi2_gradient_hessian = reduce(_Chi2GradientHessian.update, - (e.calc_chi2_gradient_hessian() - for e in self._edges), - _Chi2GradientHessian(dim)) - - self._chi2 = chi2_gradient_hessian.chi2 - - # Fill in the gradient vector - self._gradient = np.zeros(n * dim, dtype=float) - for idx, cont in chi2_gradient_hessian.gradient.items(): - self._gradient[idx * dim: (idx + 1) * dim] += cont - - # Fill in the Hessian matrix - self._hessian = lil_matrix((n * dim, n * dim), dtype=float) - for (row_idx, col_idx), cont in chi2_gradient_hessian.hessian.items(): - x_start = row_idx * dim - x_end = (row_idx + 1) * dim - y_start = col_idx * dim - y_end = (col_idx + 1) * dim - self._hessian[x_start:x_end, y_start:y_end] = cont - - if row_idx != col_idx: - x_start = col_idx * dim - x_end = (col_idx + 1) * dim - y_start = row_idx * dim - y_end = (row_idx + 1) * dim - self._hessian[x_start:x_end, y_start:y_end] = \ - np.transpose(cont) - - def optimize(self, tol=1e-4, max_iter=20, fix_first_pose=True): - r"""Optimize the :math:`\chi^2` error for the ``Graph``. - - Parameters - ---------- - tol : float - If the relative decrease in the :math:`\chi^2` error between iterations is less than ``tol``, we will stop - max_iter : int - The maximum number of iterations - fix_first_pose : bool - If ``True``, we will fix the first pose - - """ - n = len(self._vertices) - dim = len(self._vertices[0].pose.to_compact()) - - # Previous iteration's chi^2 error - chi2_prev = -1. - - # For displaying the optimization progress - print("\nIteration chi^2 rel. change") - print("--------- ----- -----------") - - for i in range(max_iter): - self._calc_chi2_gradient_hessian() - - # Check for convergence (from the previous iteration); this avoids having to calculate chi^2 twice - if i > 0: - rel_diff = (chi2_prev - self._chi2) / ( - chi2_prev + np.finfo(float).eps) - print( - "{:9d} {:20.4f} {:18.6f}".format(i, self._chi2, -rel_diff)) - if self._chi2 < chi2_prev and rel_diff < tol: - return - else: - print("{:9d} {:20.4f}".format(i, self._chi2)) - - # Update the previous iteration's chi^2 error - chi2_prev = self._chi2 - - # Hold the first pose fixed - if fix_first_pose: - self._hessian[:dim, :] = 0. - self._hessian[:, :dim] = 0. - self._hessian[:dim, :dim] += np.eye(dim) - self._gradient[:dim] = 0. - - # Solve for the updates - dx = spsolve(self._hessian, -self._gradient) - - # Apply the updates - for v, dx_i in zip(self._vertices, np.split(dx, n)): - v.pose += dx_i - - # If we reached the maximum number of iterations, print out the final iteration's results - self.calc_chi2() - rel_diff = (chi2_prev - self._chi2) / (chi2_prev + np.finfo(float).eps) - print("{:9d} {:20.4f} {:18.6f}".format( - max_iter, self._chi2, -rel_diff)) - - def to_g2o(self, outfile): - """Save the graph in .g2o format. - - Parameters - ---------- - outfile : str - The path where the graph will be saved - - """ - with open(outfile, 'w') as f: - for v in self._vertices: - f.write(v.to_g2o()) - - for e in self._edges: - f.write(e.to_g2o()) - - def plot(self, vertex_color='r', vertex_marker='o', vertex_markersize=3, - edge_color='b', title=None): - """Plot the graph. - - Parameters - ---------- - vertex_color : str - The color that will be used to plot the vertices - vertex_marker : str - The marker that will be used to plot the vertices - vertex_markersize : int - The size of the plotted vertices - edge_color : str - The color that will be used to plot the edges - title : str, None - The title that will be used for the plot - - """ - plt.figure() - - for e in self._edges: - e.plot(edge_color) - - for v in self._vertices: - v.plot(vertex_color, vertex_marker, vertex_markersize) - - if title: - plt.title(title) - - plt.show() diff --git a/SLAM/GraphBasedSLAM/graphslam/load.py b/SLAM/GraphBasedSLAM/graphslam/load.py deleted file mode 100644 index ebf42914566..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/load.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -"""Functions for loading graphs. - -""" - -import logging - -import numpy as np - -from .edge.edge_odometry import EdgeOdometry -from .graph import Graph -from .pose.se2 import PoseSE2 -from .util import upper_triangular_matrix_to_full_matrix -from .vertex import Vertex - -_LOGGER = logging.getLogger(__name__) - - -def load_g2o_se2(infile): - """Load an :math:`SE(2)` graph from a .g2o file. - - Parameters - ---------- - infile : str - The path to the .g2o file - - Returns - ------- - Graph - The loaded graph - - """ - edges = [] - vertices = [] - - with open(infile) as f: - for line in f.readlines(): - if line.startswith("VERTEX_SE2"): - numbers = line[10:].split() - arr = np.array([float(number) for number in numbers[1:]], - dtype=float) - p = PoseSE2(arr[:2], arr[2]) - v = Vertex(int(numbers[0]), p) - vertices.append(v) - continue - - if line.startswith("EDGE_SE2"): - numbers = line[9:].split() - arr = np.array([float(number) for number in numbers[2:]], - dtype=float) - vertex_ids = [int(numbers[0]), int(numbers[1])] - estimate = PoseSE2(arr[:2], arr[2]) - information = upper_triangular_matrix_to_full_matrix(arr[3:], 3) - e = EdgeOdometry(vertex_ids, information, estimate) - edges.append(e) - continue - - if line.strip(): - _LOGGER.warning("Line not supported -- '%s'", line.rstrip()) - - return Graph(edges, vertices) diff --git a/SLAM/GraphBasedSLAM/graphslam/pose/__init__.py b/SLAM/GraphBasedSLAM/graphslam/pose/__init__.py deleted file mode 100644 index afb85490871..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/pose/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam diff --git a/SLAM/GraphBasedSLAM/graphslam/pose/se2.py b/SLAM/GraphBasedSLAM/graphslam/pose/se2.py deleted file mode 100644 index 2a32e765f7d..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/pose/se2.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -r"""Representation of a pose in :math:`SE(2)`. - -""" - -import math -import numpy as np - -from ..util import neg_pi_to_pi - - -class PoseSE2(np.ndarray): - r"""A representation of a pose in :math:`SE(2)`. - - Parameters - ---------- - position : np.ndarray, list - The position in :math:`\mathbb{R}^2` - orientation : float - The angle of the pose (in radians) - - """ - - def __new__(cls, position, orientation): - obj = np.array([position[0], position[1], neg_pi_to_pi(orientation)], - dtype=float).view(cls) - return obj - - # pylint: disable=arguments-differ - def copy(self): - """Return a copy of the pose. - - Returns - ------- - PoseSE2 - A copy of the pose - - """ - return PoseSE2(self[:2], self[2]) - - def to_array(self): - """Return the pose as a numpy array. - - Returns - ------- - np.ndarray - The pose as a numpy array - - """ - return np.array(self) - - def to_compact(self): - """Return the pose as a compact numpy array. - - Returns - ------- - np.ndarray - The pose as a compact numpy array - - """ - return np.array(self) - - def to_matrix(self): - """Return the pose as an :math:`SE(2)` matrix. - - Returns - ------- - np.ndarray - The pose as an :math:`SE(2)` matrix - - """ - return np.array([[np.cos(self[2]), -np.sin(self[2]), self[0]], - [np.sin(self[2]), np.cos(self[2]), self[1]], - [0., 0., 1.]], dtype=float) - - @classmethod - def from_matrix(cls, matrix): - """Return the pose as an :math:`SE(2)` matrix. - - Parameters - ---------- - matrix : np.ndarray - The :math:`SE(2)` matrix that will be converted to a `PoseSE2` instance - - Returns - ------- - PoseSE2 - The matrix as a `PoseSE2` object - - """ - return cls([matrix[0, 2], matrix[1, 2]], - math.atan2(matrix[1, 0], matrix[0, 0])) - - # ======================================================================= # - # # - # Properties # - # # - # ======================================================================= # - @property - def position(self): - """Return the pose's position. - - Returns - ------- - np.ndarray - The position portion of the pose - - """ - return np.array(self[:2]) - - @property - def orientation(self): - """Return the pose's orientation. - - Returns - ------- - float - The angle of the pose - - """ - return self[2] - - @property - def inverse(self): - """Return the pose's inverse. - - Returns - ------- - PoseSE2 - The pose's inverse - - """ - return PoseSE2([-self[0] * np.cos(self[2]) - self[1] * np.sin(self[2]), - self[0] * np.sin(self[2]) - self[1] * np.cos(self[2])], - -self[2]) - - # ======================================================================= # - # # - # Magic Methods # - # # - # ======================================================================= # - def __add__(self, other): - r"""Add poses (i.e., pose composition): :math:`p_1 \oplus p_2`. - - Parameters - ---------- - other : PoseSE2 - The other pose - - Returns - ------- - PoseSE2 - The result of pose composition - - """ - return PoseSE2( - [self[0] + other[0] * np.cos(self[2]) - other[1] * np.sin(self[2]), - self[1] + other[0] * np.sin(self[2]) + other[1] * np.cos(self[2]) - ], neg_pi_to_pi(self[2] + other[2])) - - def __sub__(self, other): - r"""Subtract poses (i.e., inverse pose composition): :math:`p_1 \ominus p_2`. - - Parameters - ---------- - other : PoseSE2 - The other pose - - Returns - ------- - PoseSE2 - The result of inverse pose composition - - """ - return PoseSE2([(self[0] - other[0]) * np.cos(other[2]) + ( - self[1] - other[1]) * np.sin(other[2]), - (other[0] - self[0]) * np.sin(other[2]) + ( - self[1] - other[1]) * np.cos(other[2])], - neg_pi_to_pi(self[2] - other[2])) diff --git a/SLAM/GraphBasedSLAM/graphslam/util.py b/SLAM/GraphBasedSLAM/graphslam/util.py deleted file mode 100644 index 619aff20afd..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/util.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -"""Utility functions used throughout the package. - -""" - -import numpy as np - - -TWO_PI = 2 * np.pi - - -def neg_pi_to_pi(angle): - r"""Normalize ``angle`` to be in :math:`[-\pi, \pi)`. - - Parameters - ---------- - angle : float - An angle (in radians) - - Returns - ------- - float - The angle normalized to :math:`[-\pi, \pi)` - - """ - return (angle + np.pi) % (TWO_PI) - np.pi - - -def solve_for_edge_dimensionality(n): - r"""Solve for the dimensionality of an edge. - - In a .g2o file, an edge is specified as ``<estimate> <information matrix>``, where only the upper triangular portion of the matrix is provided. - - This solves the problem: - - .. math:: - - d + \frac{d (d + 1)}{2} = n - - Returns - ------- - int - The dimensionality of the edge - - """ - return int(round(np.sqrt(2 * n + 2.25) - 1.5)) - - -def upper_triangular_matrix_to_full_matrix(arr, n): - """Given an upper triangular matrix, return the full matrix. - - Parameters - ---------- - arr : np.ndarray - The upper triangular portion of the matrix - n : int - The size of the matrix - - Returns - ------- - mat : np.ndarray - The full matrix - - """ - triu0 = np.triu_indices(n, 0) - tril1 = np.tril_indices(n, -1) - - mat = np.zeros((n, n), dtype=float) - mat[triu0] = arr - mat[tril1] = mat.T[tril1] - - return mat diff --git a/SLAM/GraphBasedSLAM/graphslam/vertex.py b/SLAM/GraphBasedSLAM/graphslam/vertex.py deleted file mode 100644 index 6fb1f0d0985..00000000000 --- a/SLAM/GraphBasedSLAM/graphslam/vertex.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) 2020 Jeff Irion and contributors -# -# This file originated from the `graphslam` package: -# -# https://github.com/JeffLIrion/python-graphslam - -"""A ``Vertex`` class. - -""" - -import matplotlib.pyplot as plt - - -# pylint: disable=too-few-public-methods -class Vertex: - """A class for representing a vertex in Graph SLAM. - - Parameters - ---------- - vertex_id : int - The vertex's unique ID - pose : graphslam.pose.se2.PoseSE2 - The pose associated with the vertex - vertex_index : int, None - The vertex's index in the graph's ``vertices`` list - - Attributes - ---------- - id : int - The vertex's unique ID - index : int, None - The vertex's index in the graph's ``vertices`` list - pose : graphslam.pose.se2.PoseSE2 - The pose associated with the vertex - - """ - def __init__(self, vertex_id, pose, vertex_index=None): - self.id = vertex_id - self.pose = pose - self.index = vertex_index - - def to_g2o(self): - """Export the vertex to the .g2o format. - - Returns - ------- - str - The vertex in .g2o format - - """ - return "VERTEX_SE2 {} {} {} {}\n".format(self.id, self.pose[0], self.pose[1], self.pose[2]) - - def plot(self, color='r', marker='o', markersize=3): - """Plot the vertex. - - Parameters - ---------- - color : str - The color that will be used to plot the vertex - marker : str - The marker that will be used to plot the vertex - markersize : int - The size of the plotted vertex - - """ - x, y = self.pose.position - plt.plot(x, y, color=color, marker=marker, markersize=markersize) diff --git a/SLAM/__init__.py b/SLAM/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/SLAM/iterative_closest_point/iterative_closest_point.py b/SLAM/iterative_closest_point/iterative_closest_point.py deleted file mode 100644 index 2b44de2c071..00000000000 --- a/SLAM/iterative_closest_point/iterative_closest_point.py +++ /dev/null @@ -1,205 +0,0 @@ -""" -Iterative Closest Point (ICP) SLAM example -author: Atsushi Sakai (@Atsushi_twi), Göktuğ Karakaşlı, Shamil Gemuev -""" - -import math - -from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import -import matplotlib.pyplot as plt -import numpy as np - -# ICP parameters -EPS = 0.0001 -MAX_ITER = 100 - -show_animation = True - - -def icp_matching(previous_points, current_points): - """ - Iterative Closest Point matching - - input - previous_points: 2D or 3D points in the previous frame - current_points: 2D or 3D points in the current frame - - output - R: Rotation matrix - T: Translation vector - """ - H = None # homogeneous transformation matrix - - dError = np.inf - preError = np.inf - count = 0 - - if show_animation: - fig = plt.figure() - if previous_points.shape[0] == 3: - fig.add_subplot(111, projection='3d') - - while dError >= EPS: - count += 1 - - if show_animation: # pragma: no cover - plot_points(previous_points, current_points, fig) - plt.pause(0.1) - - indexes, error = nearest_neighbor_association(previous_points, current_points) - Rt, Tt = svd_motion_estimation(previous_points[:, indexes], current_points) - # update current points - current_points = (Rt @ current_points) + Tt[:, np.newaxis] - - dError = preError - error - print("Residual:", error) - - if dError < 0: # prevent matrix H changing, exit loop - print("Not Converge...", preError, dError, count) - break - - preError = error - H = update_homogeneous_matrix(H, Rt, Tt) - - if dError <= EPS: - print("Converge", error, dError, count) - break - elif MAX_ITER <= count: - print("Not Converge...", error, dError, count) - break - - R = np.array(H[0:-1, 0:-1]) - T = np.array(H[0:-1, -1]) - - return R, T - - -def update_homogeneous_matrix(Hin, R, T): - - r_size = R.shape[0] - H = np.zeros((r_size + 1, r_size + 1)) - - H[0:r_size, 0:r_size] = R - H[0:r_size, r_size] = T - H[r_size, r_size] = 1.0 - - if Hin is None: - return H - else: - return Hin @ H - - -def nearest_neighbor_association(previous_points, current_points): - - # calc the sum of residual errors - delta_points = previous_points - current_points - d = np.linalg.norm(delta_points, axis=0) - error = sum(d) - - # calc index with nearest neighbor assosiation - d = np.linalg.norm(np.repeat(current_points, previous_points.shape[1], axis=1) - - np.tile(previous_points, (1, current_points.shape[1])), axis=0) - indexes = np.argmin(d.reshape(current_points.shape[1], previous_points.shape[1]), axis=1) - - return indexes, error - - -def svd_motion_estimation(previous_points, current_points): - pm = np.mean(previous_points, axis=1) - cm = np.mean(current_points, axis=1) - - p_shift = previous_points - pm[:, np.newaxis] - c_shift = current_points - cm[:, np.newaxis] - - W = c_shift @ p_shift.T - u, s, vh = np.linalg.svd(W) - - R = (u @ vh).T - t = pm - (R @ cm) - - return R, t - - -def plot_points(previous_points, current_points, figure): - # for stopping simulation with the esc key. - plt.gcf().canvas.mpl_connect( - 'key_release_event', - lambda event: [exit(0) if event.key == 'escape' else None]) - if previous_points.shape[0] == 3: - plt.clf() - axes = figure.add_subplot(111, projection='3d') - axes.scatter(previous_points[0, :], previous_points[1, :], - previous_points[2, :], c="r", marker=".") - axes.scatter(current_points[0, :], current_points[1, :], - current_points[2, :], c="b", marker=".") - axes.scatter(0.0, 0.0, 0.0, c="r", marker="x") - figure.canvas.draw() - else: - plt.cla() - plt.plot(previous_points[0, :], previous_points[1, :], ".r") - plt.plot(current_points[0, :], current_points[1, :], ".b") - plt.plot(0.0, 0.0, "xr") - plt.axis("equal") - - -def main(): - print(__file__ + " start!!") - - # simulation parameters - nPoint = 1000 - fieldLength = 50.0 - motion = [0.5, 2.0, np.deg2rad(-10.0)] # movement [x[m],y[m],yaw[deg]] - - nsim = 3 # number of simulation - - for _ in range(nsim): - - # previous points - px = (np.random.rand(nPoint) - 0.5) * fieldLength - py = (np.random.rand(nPoint) - 0.5) * fieldLength - previous_points = np.vstack((px, py)) - - # current points - cx = [math.cos(motion[2]) * x - math.sin(motion[2]) * y + motion[0] - for (x, y) in zip(px, py)] - cy = [math.sin(motion[2]) * x + math.cos(motion[2]) * y + motion[1] - for (x, y) in zip(px, py)] - current_points = np.vstack((cx, cy)) - - R, T = icp_matching(previous_points, current_points) - print("R:", R) - print("T:", T) - - -def main_3d_points(): - print(__file__ + " start!!") - - # simulation parameters for 3d point set - nPoint = 1000 - fieldLength = 50.0 - motion = [0.5, 2.0, -5, np.deg2rad(-10.0)] # [x[m],y[m],z[m],roll[deg]] - - nsim = 3 # number of simulation - - for _ in range(nsim): - - # previous points - px = (np.random.rand(nPoint) - 0.5) * fieldLength - py = (np.random.rand(nPoint) - 0.5) * fieldLength - pz = (np.random.rand(nPoint) - 0.5) * fieldLength - previous_points = np.vstack((px, py, pz)) - - # current points - cx = [math.cos(motion[3]) * x - math.sin(motion[3]) * z + motion[0] - for (x, z) in zip(px, pz)] - cy = [y + motion[1] for y in py] - cz = [math.sin(motion[3]) * x + math.cos(motion[3]) * z + motion[2] - for (x, z) in zip(px, pz)] - current_points = np.vstack((cx, cy, cz)) - - R, T = icp_matching(previous_points, current_points) - print("R:", R) - print("T:", T) - - -if __name__ == '__main__': - main() - main_3d_points() diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 3ce0be729fb..00000000000 --- a/_config.yml +++ /dev/null @@ -1,2 +0,0 @@ -theme: jekyll-theme-slate -show_downloads: true diff --git a/docs/modules/2_localization/histogram_filter_localization/1.png b/_images/1.png similarity index 100% rename from docs/modules/2_localization/histogram_filter_localization/1.png rename to _images/1.png diff --git a/docs/modules/2_localization/histogram_filter_localization/2.png b/_images/2.png similarity index 100% rename from docs/modules/2_localization/histogram_filter_localization/2.png rename to _images/2.png diff --git a/docs/modules/2_localization/histogram_filter_localization/3.png b/_images/3.png similarity index 100% rename from docs/modules/2_localization/histogram_filter_localization/3.png rename to _images/3.png diff --git a/docs/modules/2_localization/histogram_filter_localization/4.png b/_images/4.png similarity index 100% rename from docs/modules/2_localization/histogram_filter_localization/4.png rename to _images/4.png diff --git a/docs/modules/4_slam/FastSLAM1/FastSLAM1_12_0.png b/_images/FastSLAM1_12_0.png similarity index 100% rename from docs/modules/4_slam/FastSLAM1/FastSLAM1_12_0.png rename to _images/FastSLAM1_12_0.png diff --git a/docs/modules/4_slam/FastSLAM1/FastSLAM1_12_1.png b/_images/FastSLAM1_12_1.png similarity index 100% rename from docs/modules/4_slam/FastSLAM1/FastSLAM1_12_1.png rename to _images/FastSLAM1_12_1.png diff --git a/docs/modules/4_slam/FastSLAM1/FastSLAM1_1_0.png b/_images/FastSLAM1_1_0.png similarity index 100% rename from docs/modules/4_slam/FastSLAM1/FastSLAM1_1_0.png rename to _images/FastSLAM1_1_0.png diff --git a/docs/modules/5_path_planning/bezier_path/Figure_1.png b/_images/Figure_1.png similarity index 100% rename from docs/modules/5_path_planning/bezier_path/Figure_1.png rename to _images/Figure_1.png diff --git a/docs/modules/5_path_planning/bezier_path/Figure_2.png b/_images/Figure_2.png similarity index 100% rename from docs/modules/5_path_planning/bezier_path/Figure_2.png rename to _images/Figure_2.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_14_1.png b/_images/Kalmanfilter_basics_14_1.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_14_1.png rename to _images/Kalmanfilter_basics_14_1.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_16_0.png b/_images/Kalmanfilter_basics_16_0.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_16_0.png rename to _images/Kalmanfilter_basics_16_0.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_19_1.png b/_images/Kalmanfilter_basics_19_1.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_19_1.png rename to _images/Kalmanfilter_basics_19_1.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_21_1.png b/_images/Kalmanfilter_basics_21_1.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_21_1.png rename to _images/Kalmanfilter_basics_21_1.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_22_0.png b/_images/Kalmanfilter_basics_22_0.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_22_0.png rename to _images/Kalmanfilter_basics_22_0.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_28_1.png b/_images/Kalmanfilter_basics_28_1.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_files/Kalmanfilter_basics_28_1.png rename to _images/Kalmanfilter_basics_28_1.png diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_2_files/Kalmanfilter_basics_2_5_0.png b/_images/Kalmanfilter_basics_2_5_0.png similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_2_files/Kalmanfilter_basics_2_5_0.png rename to _images/Kalmanfilter_basics_2_5_0.png diff --git a/docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_12_0.png b/_images/Planar_Two_Link_IK_12_0.png similarity index 100% rename from docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_12_0.png rename to _images/Planar_Two_Link_IK_12_0.png diff --git a/docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_5_0.png b/_images/Planar_Two_Link_IK_5_0.png similarity index 100% rename from docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_5_0.png rename to _images/Planar_Two_Link_IK_5_0.png diff --git a/docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_7_0.png b/_images/Planar_Two_Link_IK_7_0.png similarity index 100% rename from docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_7_0.png rename to _images/Planar_Two_Link_IK_7_0.png diff --git a/docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_9_0.png b/_images/Planar_Two_Link_IK_9_0.png similarity index 100% rename from docs/modules/7_arm_navigation/Planar_Two_Link_IK_files/Planar_Two_Link_IK_9_0.png rename to _images/Planar_Two_Link_IK_9_0.png diff --git a/docs/modules/5_path_planning/dubins_path/RLR.jpg b/_images/RLR.jpg similarity index 100% rename from docs/modules/5_path_planning/dubins_path/RLR.jpg rename to _images/RLR.jpg diff --git a/docs/modules/5_path_planning/dubins_path/RSR.jpg b/_images/RSR.jpg similarity index 100% rename from docs/modules/5_path_planning/dubins_path/RSR.jpg rename to _images/RSR.jpg diff --git a/docs/modules/5_path_planning/bspline_path/approx_and_curvature.png b/_images/approx_and_curvature.png similarity index 100% rename from docs/modules/5_path_planning/bspline_path/approx_and_curvature.png rename to _images/approx_and_curvature.png diff --git a/docs/modules/5_path_planning/bspline_path/approximation1.png b/_images/approximation1.png similarity index 100% rename from docs/modules/5_path_planning/bspline_path/approximation1.png rename to _images/approximation1.png diff --git a/docs/modules/5_path_planning/bspline_path/basis_functions.png b/_images/basis_functions.png similarity index 100% rename from docs/modules/5_path_planning/bspline_path/basis_functions.png rename to _images/basis_functions.png diff --git a/docs/modules/5_path_planning/bspline_path/bspline_path_planning.png b/_images/bspline_path_planning.png similarity index 100% rename from docs/modules/5_path_planning/bspline_path/bspline_path_planning.png rename to _images/bspline_path_planning.png diff --git a/docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_1_0.png b/_images/cgmres_nmpc_1_0.png similarity index 100% rename from docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_1_0.png rename to _images/cgmres_nmpc_1_0.png diff --git a/docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_2_0.png b/_images/cgmres_nmpc_2_0.png similarity index 100% rename from docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_2_0.png rename to _images/cgmres_nmpc_2_0.png diff --git a/docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_3_0.png b/_images/cgmres_nmpc_3_0.png similarity index 100% rename from docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_3_0.png rename to _images/cgmres_nmpc_3_0.png diff --git a/docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_4_0.png b/_images/cgmres_nmpc_4_0.png similarity index 100% rename from docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_4_0.png rename to _images/cgmres_nmpc_4_0.png diff --git a/docs/modules/5_path_planning/cubic_spline/cubic_spline_1d.png b/_images/cubic_spline_1d.png similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/cubic_spline_1d.png rename to _images/cubic_spline_1d.png diff --git a/docs/modules/5_path_planning/cubic_spline/cubic_spline_2d_curvature.png b/_images/cubic_spline_2d_curvature.png similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/cubic_spline_2d_curvature.png rename to _images/cubic_spline_2d_curvature.png diff --git a/docs/modules/5_path_planning/cubic_spline/cubic_spline_2d_path.png b/_images/cubic_spline_2d_path.png similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/cubic_spline_2d_path.png rename to _images/cubic_spline_2d_path.png diff --git a/docs/modules/5_path_planning/cubic_spline/cubic_spline_2d_yaw.png b/_images/cubic_spline_2d_yaw.png similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/cubic_spline_2d_yaw.png rename to _images/cubic_spline_2d_yaw.png diff --git a/docs/modules/11_utils/plot/curvature_plot.png b/_images/curvature_plot.png similarity index 100% rename from docs/modules/11_utils/plot/curvature_plot.png rename to _images/curvature_plot.png diff --git a/docs/_static/img/doc_ci.png b/_images/doc_ci.png similarity index 100% rename from docs/_static/img/doc_ci.png rename to _images/doc_ci.png diff --git a/docs/modules/5_path_planning/dubins_path/dubins_path.jpg b/_images/dubins_path.jpg similarity index 100% rename from docs/modules/5_path_planning/dubins_path/dubins_path.jpg rename to _images/dubins_path.jpg diff --git a/docs/modules/4_slam/ekf_slam/ekf_slam_1_0.png b/_images/ekf_slam_1_0.png similarity index 100% rename from docs/modules/4_slam/ekf_slam/ekf_slam_1_0.png rename to _images/ekf_slam_1_0.png diff --git a/docs/modules/2_localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_1_0.png b/_images/extended_kalman_filter_localization_1_0.png similarity index 100% rename from docs/modules/2_localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_1_0.png rename to _images/extended_kalman_filter_localization_1_0.png diff --git a/docs/modules/3_mapping/point_cloud_sampling/farthest_point_sampling.png b/_images/farthest_point_sampling.png similarity index 100% rename from docs/modules/3_mapping/point_cloud_sampling/farthest_point_sampling.png rename to _images/farthest_point_sampling.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_13_0.png b/_images/graphSLAM_SE2_example_13_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_13_0.png rename to _images/graphSLAM_SE2_example_13_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_15_0.png b/_images/graphSLAM_SE2_example_15_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_15_0.png rename to _images/graphSLAM_SE2_example_15_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_16_0.png b/_images/graphSLAM_SE2_example_16_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_16_0.png rename to _images/graphSLAM_SE2_example_16_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_4_0.png b/_images/graphSLAM_SE2_example_4_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_4_0.png rename to _images/graphSLAM_SE2_example_4_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_8_0.png b/_images/graphSLAM_SE2_example_8_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_8_0.png rename to _images/graphSLAM_SE2_example_8_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_9_0.png b/_images/graphSLAM_SE2_example_9_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_SE2_example_files/graphSLAM_SE2_example_9_0.png rename to _images/graphSLAM_SE2_example_9_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_11_1.png b/_images/graphSLAM_doc_11_1.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_11_1.png rename to _images/graphSLAM_doc_11_1.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_11_2.png b/_images/graphSLAM_doc_11_2.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_11_2.png rename to _images/graphSLAM_doc_11_2.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_2_0.png b/_images/graphSLAM_doc_2_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_2_0.png rename to _images/graphSLAM_doc_2_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_2_2.png b/_images/graphSLAM_doc_2_2.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_2_2.png rename to _images/graphSLAM_doc_2_2.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_4_0.png b/_images/graphSLAM_doc_4_0.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_4_0.png rename to _images/graphSLAM_doc_4_0.png diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_9_1.png b/_images/graphSLAM_doc_9_1.png similarity index 100% rename from docs/modules/4_slam/graph_slam/graphSLAM_doc_files/graphSLAM_doc_9_1.png rename to _images/graphSLAM_doc_9_1.png diff --git a/docs/modules/3_mapping/ndt_map/grid_clustering.png b/_images/grid_clustering.png similarity index 100% rename from docs/modules/3_mapping/ndt_map/grid_clustering.png rename to _images/grid_clustering.png diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/grid_map_example.png b/_images/grid_map_example.png similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/grid_map_example.png rename to _images/grid_map_example.png diff --git a/docs/modules/5_path_planning/bspline_path/interp_and_curvature.png b/_images/interp_and_curvature.png similarity index 100% rename from docs/modules/5_path_planning/bspline_path/interp_and_curvature.png rename to _images/interp_and_curvature.png diff --git a/docs/modules/5_path_planning/bspline_path/interpolation1.png b/_images/interpolation1.png similarity index 100% rename from docs/modules/5_path_planning/bspline_path/interpolation1.png rename to _images/interpolation1.png diff --git a/docs/modules/10_inverted_pendulum/inverted-pendulum.png b/_images/inverted-pendulum.png similarity index 100% rename from docs/modules/10_inverted_pendulum/inverted-pendulum.png rename to _images/inverted-pendulum.png diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_12_0.png b/_images/lidar_to_grid_map_tutorial_12_0.png similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_12_0.png rename to _images/lidar_to_grid_map_tutorial_12_0.png diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_14_1.png b/_images/lidar_to_grid_map_tutorial_14_1.png similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_14_1.png rename to _images/lidar_to_grid_map_tutorial_14_1.png diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_5_0.png b/_images/lidar_to_grid_map_tutorial_5_0.png similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_5_0.png rename to _images/lidar_to_grid_map_tutorial_5_0.png diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_7_0.png b/_images/lidar_to_grid_map_tutorial_7_0.png similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_7_0.png rename to _images/lidar_to_grid_map_tutorial_7_0.png diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_8_0.png b/_images/lidar_to_grid_map_tutorial_8_0.png similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_8_0.png rename to _images/lidar_to_grid_map_tutorial_8_0.png diff --git a/docs/modules/5_path_planning/model_predictive_trajectory_generator/lookup_table.png b/_images/lookup_table.png similarity index 100% rename from docs/modules/5_path_planning/model_predictive_trajectory_generator/lookup_table.png rename to _images/lookup_table.png diff --git a/docs/modules/3_mapping/ndt_map/ndt_map1.png b/_images/ndt_map1.png similarity index 100% rename from docs/modules/3_mapping/ndt_map/ndt_map1.png rename to _images/ndt_map1.png diff --git a/docs/modules/3_mapping/ndt_map/ndt_map2.png b/_images/ndt_map2.png similarity index 100% rename from docs/modules/3_mapping/ndt_map/ndt_map2.png rename to _images/ndt_map2.png diff --git a/docs/modules/3_mapping/normal_vector_estimation/normal_vector_calc.png b/_images/normal_vector_calc.png similarity index 100% rename from docs/modules/3_mapping/normal_vector_estimation/normal_vector_calc.png rename to _images/normal_vector_calc.png diff --git a/docs/modules/3_mapping/point_cloud_sampling/poisson_disk_sampling.png b/_images/poisson_disk_sampling.png similarity index 100% rename from docs/modules/3_mapping/point_cloud_sampling/poisson_disk_sampling.png rename to _images/poisson_disk_sampling.png diff --git a/docs/modules/3_mapping/normal_vector_estimation/ransac_normal_vector_estimation.png b/_images/ransac_normal_vector_estimation.png similarity index 100% rename from docs/modules/3_mapping/normal_vector_estimation/ransac_normal_vector_estimation.png rename to _images/ransac_normal_vector_estimation.png diff --git a/docs/modules/3_mapping/ndt_map/raw_observations.png b/_images/raw_observations.png similarity index 100% rename from docs/modules/3_mapping/ndt_map/raw_observations.png rename to _images/raw_observations.png diff --git a/docs/modules/5_path_planning/rrt/rrt_star/rrt_star_1_0.png b/_images/rrt_star_1_0.png similarity index 100% rename from docs/modules/5_path_planning/rrt/rrt_star/rrt_star_1_0.png rename to _images/rrt_star_1_0.png diff --git a/docs/modules/5_path_planning/cubic_spline/spline.png b/_images/spline.png similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/spline.png rename to _images/spline.png diff --git a/docs/modules/5_path_planning/cubic_spline/spline_continuity.png b/_images/spline_continuity.png similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/spline_continuity.png rename to _images/spline_continuity.png diff --git a/docs/modules/5_path_planning/visibility_road_map_planner/step0.png b/_images/step0.png similarity index 100% rename from docs/modules/5_path_planning/visibility_road_map_planner/step0.png rename to _images/step0.png diff --git a/docs/modules/5_path_planning/visibility_road_map_planner/step1.png b/_images/step1.png similarity index 100% rename from docs/modules/5_path_planning/visibility_road_map_planner/step1.png rename to _images/step1.png diff --git a/docs/modules/5_path_planning/visibility_road_map_planner/step2.png b/_images/step2.png similarity index 100% rename from docs/modules/5_path_planning/visibility_road_map_planner/step2.png rename to _images/step2.png diff --git a/docs/modules/5_path_planning/visibility_road_map_planner/step3.png b/_images/step3.png similarity index 100% rename from docs/modules/5_path_planning/visibility_road_map_planner/step3.png rename to _images/step3.png diff --git a/docs/modules/3_mapping/point_cloud_sampling/voxel_point_sampling.png b/_images/voxel_point_sampling.png similarity index 100% rename from docs/modules/3_mapping/point_cloud_sampling/voxel_point_sampling.png rename to _images/voxel_point_sampling.png diff --git a/_modules/Mapping/ndt_map/ndt_map.html b/_modules/Mapping/ndt_map/ndt_map.html new file mode 100644 index 00000000000..cd4b16eea0a --- /dev/null +++ b/_modules/Mapping/ndt_map/ndt_map.html @@ -0,0 +1,268 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Mapping.ndt_map.ndt_map — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>Mapping.ndt_map.ndt_map</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for Mapping.ndt_map.ndt_map</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> +<span class="sd">Normal Distribution Transform (NDTGrid) mapping sample</span> +<span class="sd">"""</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span> + +<span class="kn">from</span> <span class="nn">Mapping.grid_map_lib.grid_map_lib</span> <span class="kn">import</span> <span class="n">GridMap</span> +<span class="kn">from</span> <span class="nn">utils.plot</span> <span class="kn">import</span> <span class="n">plot_covariance_ellipse</span> + + +<div class="viewcode-block" id="NDTMap"><a class="viewcode-back" href="../../../modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap">[docs]</a><span class="k">class</span> <span class="nc">NDTMap</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Normal Distribution Transform (NDT) map class</span> + +<span class="sd"> :param ox: obstacle x position list</span> +<span class="sd"> :param oy: obstacle y position list</span> +<span class="sd"> :param resolution: grid resolution [m]</span> +<span class="sd"> """</span> + +<div class="viewcode-block" id="NDTMap.NDTGrid"><a class="viewcode-back" href="../../../modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid">[docs]</a> <span class="k">class</span> <span class="nc">NDTGrid</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> NDT grid</span> +<span class="sd"> """</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="c1">#: Number of points in the NDTGrid grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">n_points</span> <span class="o">=</span> <span class="mi">0</span> + <span class="c1">#: Mean x position of points in the NDTGrid cell</span> + <span class="bp">self</span><span class="o">.</span><span class="n">mean_x</span> <span class="o">=</span> <span class="kc">None</span> + <span class="c1">#: Mean y position of points in the NDTGrid cell</span> + <span class="bp">self</span><span class="o">.</span><span class="n">mean_y</span> <span class="o">=</span> <span class="kc">None</span> + <span class="c1">#: Center x position of the NDT grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">center_grid_x</span> <span class="o">=</span> <span class="kc">None</span> + <span class="c1">#: Center y position of the NDT grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">center_grid_y</span> <span class="o">=</span> <span class="kc">None</span> + <span class="c1">#: Covariance matrix of the NDT grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">covariance</span> <span class="o">=</span> <span class="kc">None</span> + <span class="c1">#: Eigen vectors of the NDT grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">eig_vec</span> <span class="o">=</span> <span class="kc">None</span> + <span class="c1">#: Eigen values of the NDT grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">eig_values</span> <span class="o">=</span> <span class="kc">None</span></div> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">,</span> <span class="n">resolution</span><span class="p">):</span> + <span class="c1">#: Minimum number of points in the NDT grid</span> + <span class="bp">self</span><span class="o">.</span><span class="n">min_n_points</span> <span class="o">=</span> <span class="mi">3</span> + <span class="c1">#: Resolution of the NDT grid [m]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">resolution</span> <span class="o">=</span> <span class="n">resolution</span> + <span class="n">width</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="nb">max</span><span class="p">(</span><span class="n">ox</span><span class="p">)</span> <span class="o">-</span> <span class="nb">min</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span><span class="o">/</span><span class="n">resolution</span><span class="p">)</span> <span class="o">+</span> <span class="mi">3</span> <span class="c1"># rounding up + right and left margin</span> + <span class="n">height</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="nb">max</span><span class="p">(</span><span class="n">oy</span><span class="p">)</span> <span class="o">-</span> <span class="nb">min</span><span class="p">(</span><span class="n">oy</span><span class="p">))</span><span class="o">/</span><span class="n">resolution</span><span class="p">)</span> <span class="o">+</span> <span class="mi">3</span> + <span class="n">center_x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">ox</span><span class="p">)</span> + <span class="n">center_y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">oy</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">ox</span> <span class="o">=</span> <span class="n">ox</span> + <span class="bp">self</span><span class="o">.</span><span class="n">oy</span> <span class="o">=</span> <span class="n">oy</span> + <span class="c1">#: NDT grid index map</span> + <span class="bp">self</span><span class="o">.</span><span class="n">grid_index_map</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_create_grid_index_map</span><span class="p">(</span><span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">)</span> + + <span class="c1">#: NDT grid map. Each grid contains NDTGrid object</span> + <span class="bp">self</span><span class="o">.</span><span class="n">_construct_grid_map</span><span class="p">(</span><span class="n">center_x</span><span class="p">,</span> <span class="n">center_y</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">,</span> <span class="n">resolution</span><span class="p">,</span> <span class="n">width</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">_construct_grid_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">center_x</span><span class="p">,</span> <span class="n">center_y</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">,</span> <span class="n">resolution</span><span class="p">,</span> <span class="n">width</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">grid_map</span> <span class="o">=</span> <span class="n">GridMap</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">resolution</span><span class="p">,</span> <span class="n">center_x</span><span class="p">,</span> <span class="n">center_y</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">NDTGrid</span><span class="p">())</span> + <span class="k">for</span> <span class="n">grid_index</span><span class="p">,</span> <span class="n">inds</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">grid_index_map</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> + <span class="n">ndt</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">NDTGrid</span><span class="p">()</span> + <span class="n">ndt</span><span class="o">.</span><span class="n">n_points</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">inds</span><span class="p">)</span> + <span class="k">if</span> <span class="n">ndt</span><span class="o">.</span><span class="n">n_points</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_n_points</span><span class="p">:</span> + <span class="n">ndt</span><span class="o">.</span><span class="n">mean_x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">ox</span><span class="p">[</span><span class="n">inds</span><span class="p">])</span> + <span class="n">ndt</span><span class="o">.</span><span class="n">mean_y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">oy</span><span class="p">[</span><span class="n">inds</span><span class="p">])</span> + <span class="n">ndt</span><span class="o">.</span><span class="n">center_grid_x</span><span class="p">,</span> <span class="n">ndt</span><span class="o">.</span><span class="n">center_grid_y</span> <span class="o">=</span> \ + <span class="bp">self</span><span class="o">.</span><span class="n">grid_map</span><span class="o">.</span><span class="n">calc_grid_central_xy_position_from_grid_index</span><span class="p">(</span><span class="n">grid_index</span><span class="p">)</span> + <span class="n">ndt</span><span class="o">.</span><span class="n">covariance</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cov</span><span class="p">(</span><span class="n">ox</span><span class="p">[</span><span class="n">inds</span><span class="p">],</span> <span class="n">oy</span><span class="p">[</span><span class="n">inds</span><span class="p">])</span> + <span class="n">ndt</span><span class="o">.</span><span class="n">eig_values</span><span class="p">,</span> <span class="n">ndt</span><span class="o">.</span><span class="n">eig_vec</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">eig</span><span class="p">(</span><span class="n">ndt</span><span class="o">.</span><span class="n">covariance</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">grid_map</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="n">grid_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">ndt</span> + + <span class="k">def</span> <span class="nf">_create_grid_index_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">):</span> + <span class="n">grid_index_map</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">)):</span> + <span class="n">grid_index</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">grid_map</span><span class="o">.</span><span class="n">calc_grid_index_from_xy_pos</span><span class="p">(</span><span class="n">ox</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">oy</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> + <span class="n">grid_index_map</span><span class="p">[</span><span class="n">grid_index</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> + <span class="k">return</span> <span class="n">grid_index_map</span></div> + + +<span class="k">def</span> <span class="nf">create_dummy_observation_data</span><span class="p">():</span> + <span class="n">ox</span> <span class="o">=</span> <span class="p">[]</span> + <span class="n">oy</span> <span class="o">=</span> <span class="p">[]</span> + <span class="c1"># left corridor</span> + <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="mi">50</span><span class="p">,</span> <span class="mi">50</span><span class="p">):</span> + <span class="n">ox</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="o">-</span><span class="mf">20.0</span><span class="p">)</span> + <span class="n">oy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> + <span class="c1"># right corridor 1</span> + <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="mi">50</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span> + <span class="n">ox</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mf">20.0</span><span class="p">)</span> + <span class="n">oy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> + <span class="c1"># right corridor 2</span> + <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">50</span><span class="p">):</span> + <span class="n">ox</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">oy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> + <span class="c1"># right corridor 3</span> + <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">50</span><span class="p">):</span> + <span class="n">ox</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">oy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">/</span><span class="mf">2.0</span><span class="o">+</span><span class="mi">10</span><span class="p">)</span> + <span class="c1"># right corridor 4</span> + <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">50</span><span class="p">):</span> + <span class="n">ox</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span> + <span class="n">oy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> + <span class="n">ox</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">ox</span><span class="p">)</span> + <span class="n">oy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">oy</span><span class="p">)</span> + <span class="c1"># Adding random noize</span> + <span class="n">ox</span> <span class="o">+=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="o">*</span> <span class="mf">1.0</span> + <span class="n">oy</span> <span class="o">+=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="o">*</span> <span class="mf">1.0</span> + <span class="k">return</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span> + + +<span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + <span class="nb">print</span><span class="p">(</span><span class="vm">__file__</span> <span class="o">+</span> <span class="s2">" start!!"</span><span class="p">)</span> + + <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span> <span class="o">=</span> <span class="n">create_dummy_observation_data</span><span class="p">()</span> + <span class="n">grid_resolution</span> <span class="o">=</span> <span class="mf">10.0</span> + <span class="n">ndt_map</span> <span class="o">=</span> <span class="n">NDTMap</span><span class="p">(</span><span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">,</span> <span class="n">grid_resolution</span><span class="p">)</span> + + <span class="c1"># plot raw observation</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">,</span> <span class="s2">".r"</span><span class="p">)</span> + + <span class="c1"># plot grid clustering</span> + <span class="p">[</span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">ox</span><span class="p">[</span><span class="n">inds</span><span class="p">],</span> <span class="n">oy</span><span class="p">[</span><span class="n">inds</span><span class="p">],</span> <span class="s2">"x"</span><span class="p">)</span> <span class="k">for</span> <span class="n">inds</span> <span class="ow">in</span> <span class="n">ndt_map</span><span class="o">.</span><span class="n">grid_index_map</span><span class="o">.</span><span class="n">values</span><span class="p">()]</span> + + <span class="c1"># plot ndt grid map</span> + <span class="p">[</span><span class="n">plot_covariance_ellipse</span><span class="p">(</span><span class="n">ndt</span><span class="o">.</span><span class="n">mean_x</span><span class="p">,</span> <span class="n">ndt</span><span class="o">.</span><span class="n">mean_y</span><span class="p">,</span> <span class="n">ndt</span><span class="o">.</span><span class="n">covariance</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"-k"</span><span class="p">)</span> <span class="k">for</span> <span class="n">ndt</span> <span class="ow">in</span> <span class="n">ndt_map</span><span class="o">.</span><span class="n">grid_map</span><span class="o">.</span><span class="n">data</span> <span class="k">if</span> <span class="n">ndt</span><span class="o">.</span><span class="n">n_points</span> <span class="o">></span> <span class="mi">0</span><span class="p">]</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="n">main</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/Mapping/normal_vector_estimation/normal_vector_estimation.html b/_modules/Mapping/normal_vector_estimation/normal_vector_estimation.html new file mode 100644 index 00000000000..227f8484596 --- /dev/null +++ b/_modules/Mapping/normal_vector_estimation/normal_vector_estimation.html @@ -0,0 +1,310 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Mapping.normal_vector_estimation.normal_vector_estimation — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>Mapping.normal_vector_estimation.normal_vector_estimation</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for Mapping.normal_vector_estimation.normal_vector_estimation</h1><div class="highlight"><pre> +<span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">pyplot</span> <span class="k">as</span> <span class="n">plt</span> + +<span class="kn">from</span> <span class="nn">utils.plot</span> <span class="kn">import</span> <span class="n">plot_3d_vector_arrow</span><span class="p">,</span> <span class="n">plot_triangle</span><span class="p">,</span> <span class="n">set_equal_3d_axis</span> + +<span class="n">show_animation</span> <span class="o">=</span> <span class="kc">True</span> + + +<div class="viewcode-block" id="calc_normal_vector"><a class="viewcode-back" href="../../../modules/mapping/normal_vector_estimation/normal_vector_estimation.html#Mapping.normal_vector_estimation.normal_vector_estimation.calc_normal_vector">[docs]</a><span class="k">def</span> <span class="nf">calc_normal_vector</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""Calculate normal vector of triangle</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> p1 : np.array</span> +<span class="sd"> 3D point</span> +<span class="sd"> p2 : np.array</span> +<span class="sd"> 3D point</span> +<span class="sd"> p3 : np.array</span> +<span class="sd"> 3D point</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> normal_vector : np.array</span> +<span class="sd"> normal vector (3,)</span> + +<span class="sd"> """</span> + <span class="c1"># calculate two vectors of triangle</span> + <span class="n">v1</span> <span class="o">=</span> <span class="n">p2</span> <span class="o">-</span> <span class="n">p1</span> + <span class="n">v2</span> <span class="o">=</span> <span class="n">p3</span> <span class="o">-</span> <span class="n">p1</span> + + <span class="c1"># calculate normal vector</span> + <span class="n">normal_vector</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cross</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">)</span> + + <span class="c1"># normalize vector</span> + <span class="n">normal_vector</span> <span class="o">=</span> <span class="n">normal_vector</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">normal_vector</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">normal_vector</span></div> + + +<span class="k">def</span> <span class="nf">sample_3d_points_from_a_plane</span><span class="p">(</span><span class="n">num_samples</span><span class="p">,</span> <span class="n">normal</span><span class="p">):</span> + <span class="n">points_2d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="p">(</span><span class="n">num_samples</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> <span class="c1"># 2D points on a plane</span> + <span class="n">d</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">points_2d</span><span class="p">)):</span> + <span class="n">point_3d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">points_2d</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span> + <span class="n">d</span> <span class="o">+=</span> <span class="n">normal</span> <span class="o">@</span> <span class="n">point_3d</span> + <span class="n">d</span> <span class="o">/=</span> <span class="nb">len</span><span class="p">(</span><span class="n">points_2d</span><span class="p">)</span> + + <span class="n">points_3d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">points_2d</span><span class="p">),</span> <span class="mi">3</span><span class="p">))</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">points_2d</span><span class="p">)):</span> + <span class="n">point_2d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">points_2d</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span> + <span class="n">projection_length</span> <span class="o">=</span> <span class="p">(</span><span class="n">d</span> <span class="o">-</span> <span class="n">normal</span> <span class="o">@</span> <span class="n">point_2d</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">normal</span><span class="p">)</span> + <span class="n">points_3d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">point_2d</span> <span class="o">+</span> <span class="n">projection_length</span> <span class="o">*</span> <span class="n">normal</span> + + <span class="k">return</span> <span class="n">points_3d</span> + + +<span class="k">def</span> <span class="nf">distance_to_plane</span><span class="p">(</span><span class="n">point</span><span class="p">,</span> <span class="n">normal</span><span class="p">,</span> <span class="n">origin</span><span class="p">):</span> + <span class="n">dot_product</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">normal</span><span class="p">,</span> <span class="n">point</span><span class="p">)</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">normal</span><span class="p">,</span> <span class="n">origin</span><span class="p">)</span> + <span class="k">if</span> <span class="n">np</span><span class="o">.</span><span class="n">isclose</span><span class="p">(</span><span class="n">dot_product</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span> + <span class="k">return</span> <span class="mf">0.0</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">distance</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">dot_product</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">normal</span><span class="p">)</span> + <span class="k">return</span> <span class="n">distance</span> + + +<div class="viewcode-block" id="ransac_normal_vector_estimation"><a class="viewcode-back" href="../../../modules/mapping/normal_vector_estimation/normal_vector_estimation.html#Mapping.normal_vector_estimation.normal_vector_estimation.ransac_normal_vector_estimation">[docs]</a><span class="k">def</span> <span class="nf">ransac_normal_vector_estimation</span><span class="p">(</span><span class="n">points_3d</span><span class="p">,</span> <span class="n">inlier_radio_th</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> + <span class="n">inlier_dist</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="mf">0.99</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> RANSAC based normal vector estimation</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> points_3d : np.array</span> +<span class="sd"> 3D points (N, 3)</span> +<span class="sd"> inlier_radio_th : float</span> +<span class="sd"> Inlier ratio threshold. If inlier ratio is larger than this value,</span> +<span class="sd"> the iteration is stopped. Default is 0.7.</span> +<span class="sd"> inlier_dist : float</span> +<span class="sd"> Inlier distance threshold. If distance between points and estimated</span> +<span class="sd"> plane is smaller than this value, the point is inlier. Default is 0.1.</span> +<span class="sd"> p : float</span> +<span class="sd"> Probability that at least one of the sets of random samples does not</span> +<span class="sd"> include an outlier. If this probability is near 1, the iteration</span> +<span class="sd"> number is large. Default is 0.99.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> center_vector : np.array</span> +<span class="sd"> Center of estimated plane. (3,)</span> +<span class="sd"> normal_vector : np.array</span> +<span class="sd"> Normal vector of estimated plane. (3,)</span> + +<span class="sd"> """</span> + <span class="n">center</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">points_3d</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> + + <span class="n">max_iter</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">floor</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="mf">1.0</span><span class="o">-</span><span class="n">p</span><span class="p">)</span><span class="o">/</span><span class="n">np</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="mf">1.0</span><span class="o">-</span><span class="p">(</span><span class="mf">1.0</span><span class="o">-</span><span class="n">inlier_radio_th</span><span class="p">)</span><span class="o">**</span><span class="mi">3</span><span class="p">)))</span> + + <span class="k">for</span> <span class="n">ite</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">max_iter</span><span class="p">):</span> + <span class="c1"># Random sampling</span> + <span class="n">sampled_ids</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">points_3d</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">size</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> + <span class="n">replace</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> + <span class="n">sampled_points</span> <span class="o">=</span> <span class="n">points_3d</span><span class="p">[</span><span class="n">sampled_ids</span><span class="p">,</span> <span class="p">:]</span> + <span class="n">p1</span> <span class="o">=</span> <span class="n">sampled_points</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:]</span> + <span class="n">p2</span> <span class="o">=</span> <span class="n">sampled_points</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:]</span> + <span class="n">p3</span> <span class="o">=</span> <span class="n">sampled_points</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="p">:]</span> + <span class="n">normal_vector</span> <span class="o">=</span> <span class="n">calc_normal_vector</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">)</span> + + <span class="c1"># calc inlier ratio</span> + <span class="n">n_inliner</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">points_3d</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span> + <span class="n">p</span> <span class="o">=</span> <span class="n">points_3d</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> + <span class="k">if</span> <span class="n">distance_to_plane</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">normal_vector</span><span class="p">,</span> <span class="n">center</span><span class="p">)</span> <span class="o"><=</span> <span class="n">inlier_dist</span><span class="p">:</span> + <span class="n">n_inliner</span> <span class="o">+=</span> <span class="mi">1</span> + <span class="n">inlier_ratio</span> <span class="o">=</span> <span class="n">n_inliner</span> <span class="o">/</span> <span class="n">points_3d</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Iter:</span><span class="si">{</span><span class="n">ite</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">inlier_ratio</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + <span class="k">if</span> <span class="n">inlier_ratio</span> <span class="o">></span> <span class="n">inlier_radio_th</span><span class="p">:</span> + <span class="k">return</span> <span class="n">center</span><span class="p">,</span> <span class="n">normal_vector</span> + + <span class="k">return</span> <span class="n">center</span><span class="p">,</span> <span class="kc">None</span></div> + + +<span class="k">def</span> <span class="nf">main1</span><span class="p">():</span> + <span class="n">p1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">])</span> + <span class="n">p2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">])</span> + <span class="n">p3</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">])</span> + + <span class="n">center</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">([</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> + <span class="n">normal_vector</span> <span class="o">=</span> <span class="n">calc_normal_vector</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">center</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">normal_vector</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">show_animation</span><span class="p">:</span> + <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> + <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">projection</span><span class="o">=</span><span class="s1">'3d'</span><span class="p">)</span> + <span class="n">set_equal_3d_axis</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">])</span> + <span class="n">plot_triangle</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">,</span> <span class="n">ax</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">center</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">center</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">center</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="s2">"ro"</span><span class="p">)</span> + <span class="n">plot_3d_vector_arrow</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">center</span> <span class="o">+</span> <span class="n">normal_vector</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">def</span> <span class="nf">main2</span><span class="p">(</span><span class="n">rng</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> + <span class="n">true_normal</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span> + <span class="n">true_normal</span> <span class="o">=</span> <span class="n">true_normal</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">true_normal</span><span class="p">)</span> + <span class="n">num_samples</span> <span class="o">=</span> <span class="mi">100</span> + <span class="n">noise_scale</span> <span class="o">=</span> <span class="mf">0.1</span> + + <span class="n">points_3d</span> <span class="o">=</span> <span class="n">sample_3d_points_from_a_plane</span><span class="p">(</span><span class="n">num_samples</span><span class="p">,</span> <span class="n">true_normal</span><span class="p">)</span> + <span class="c1"># add random noise</span> + <span class="n">points_3d</span> <span class="o">+=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">points_3d</span><span class="o">.</span><span class="n">shape</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="n">noise_scale</span><span class="p">)</span> + + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">points_3d</span><span class="o">.</span><span class="n">shape</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + + <span class="n">center</span><span class="p">,</span> <span class="n">estimated_normal</span> <span class="o">=</span> <span class="n">ransac_normal_vector_estimation</span><span class="p">(</span> + <span class="n">points_3d</span><span class="p">,</span> <span class="n">inlier_dist</span><span class="o">=</span><span class="n">noise_scale</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">estimated_normal</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"Failed to estimate normal vector"</span><span class="p">)</span> + <span class="k">return</span> + + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">true_normal</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">estimated_normal</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">show_animation</span><span class="p">:</span> + <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> + <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">projection</span><span class="o">=</span><span class="s1">'3d'</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">points_3d</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">points_3d</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">points_3d</span><span class="p">[:,</span> <span class="mi">2</span><span class="p">],</span> <span class="s2">".r"</span><span class="p">)</span> + <span class="n">plot_3d_vector_arrow</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">center</span> <span class="o">+</span> <span class="n">true_normal</span><span class="p">)</span> + <span class="n">plot_3d_vector_arrow</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">center</span><span class="p">,</span> <span class="n">center</span> <span class="o">+</span> <span class="n">estimated_normal</span><span class="p">)</span> + <span class="n">set_equal_3d_axis</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="p">[</span><span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">])</span> + <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"RANSAC based Normal vector estimation"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="c1"># main1()</span> + <span class="n">main2</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/Mapping/point_cloud_sampling/point_cloud_sampling.html b/_modules/Mapping/point_cloud_sampling/point_cloud_sampling.html new file mode 100644 index 00000000000..b1e734dc62d --- /dev/null +++ b/_modules/Mapping/point_cloud_sampling/point_cloud_sampling.html @@ -0,0 +1,301 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Mapping.point_cloud_sampling.point_cloud_sampling — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>Mapping.point_cloud_sampling.point_cloud_sampling</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for Mapping.point_cloud_sampling.point_cloud_sampling</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> +<span class="sd">Point cloud sampling example codes. This code supports</span> +<span class="sd">- Voxel point sampling</span> +<span class="sd">- Farthest point sampling</span> +<span class="sd">- Poisson disk sampling</span> + +<span class="sd">"""</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">numpy.typing</span> <span class="k">as</span> <span class="nn">npt</span> +<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span> + +<span class="n">do_plot</span> <span class="o">=</span> <span class="kc">True</span> + + +<div class="viewcode-block" id="voxel_point_sampling"><a class="viewcode-back" href="../../../modules/mapping/point_cloud_sampling/point_cloud_sampling.html#Mapping.point_cloud_sampling.point_cloud_sampling.voxel_point_sampling">[docs]</a><span class="k">def</span> <span class="nf">voxel_point_sampling</span><span class="p">(</span><span class="n">original_points</span><span class="p">:</span> <span class="n">npt</span><span class="o">.</span><span class="n">NDArray</span><span class="p">,</span> <span class="n">voxel_size</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Voxel Point Sampling function.</span> +<span class="sd"> This function sample N-dimensional points with voxel grid.</span> +<span class="sd"> Points in a same voxel grid will be merged by mean operation for sampling.</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> original_points : (M, N) N-dimensional points for sampling.</span> +<span class="sd"> The number of points is M.</span> +<span class="sd"> voxel_size : voxel grid size</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> sampled points (M', N)</span> +<span class="sd"> """</span> + <span class="n">voxel_dict</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">original_points</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span> + <span class="n">xyz</span> <span class="o">=</span> <span class="n">original_points</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:]</span> + <span class="n">xyz_index</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">xyz</span> <span class="o">//</span> <span class="n">voxel_size</span><span class="p">)</span> + <span class="n">voxel_dict</span><span class="p">[</span><span class="n">xyz_index</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">xyz</span><span class="p">)</span> + <span class="n">points</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">([</span><span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">voxel_dict</span><span class="o">.</span><span class="n">values</span><span class="p">()])</span> + <span class="k">return</span> <span class="n">points</span></div> + + +<div class="viewcode-block" id="farthest_point_sampling"><a class="viewcode-back" href="../../../modules/mapping/point_cloud_sampling/point_cloud_sampling.html#Mapping.point_cloud_sampling.point_cloud_sampling.farthest_point_sampling">[docs]</a><span class="k">def</span> <span class="nf">farthest_point_sampling</span><span class="p">(</span><span class="n">orig_points</span><span class="p">:</span> <span class="n">npt</span><span class="o">.</span><span class="n">NDArray</span><span class="p">,</span> + <span class="n">n_points</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">seed</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Farthest point sampling function</span> +<span class="sd"> This function sample N-dimensional points with the farthest point policy.</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> orig_points : (M, N) N-dimensional points for sampling.</span> +<span class="sd"> The number of points is M.</span> +<span class="sd"> n_points : number of points for sampling</span> +<span class="sd"> seed : random seed number</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> sampled points (n_points, N)</span> + +<span class="sd"> """</span> + <span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span> + <span class="n">n_orig_points</span> <span class="o">=</span> <span class="n">orig_points</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">first_point_id</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">n_orig_points</span><span class="p">))</span> + <span class="n">min_distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">ones</span><span class="p">(</span><span class="n">n_orig_points</span><span class="p">)</span> <span class="o">*</span> <span class="nb">float</span><span class="p">(</span><span class="s2">"inf"</span><span class="p">)</span> + <span class="n">selected_ids</span> <span class="o">=</span> <span class="p">[</span><span class="n">first_point_id</span><span class="p">]</span> + <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">selected_ids</span><span class="p">)</span> <span class="o"><</span> <span class="n">n_points</span><span class="p">:</span> + <span class="n">base_point</span> <span class="o">=</span> <span class="n">orig_points</span><span class="p">[</span><span class="n">selected_ids</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="p">:]</span> + <span class="n">distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">orig_points</span><span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">newaxis</span><span class="p">,</span> <span class="p">:]</span> <span class="o">-</span> <span class="n">base_point</span><span class="p">,</span> + <span class="n">axis</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span> + <span class="n">min_distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">minimum</span><span class="p">(</span><span class="n">min_distances</span><span class="p">,</span> <span class="n">distances</span><span class="p">)</span> + <span class="n">distances_rank</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argsort</span><span class="p">(</span><span class="o">-</span><span class="n">min_distances</span><span class="p">)</span> <span class="c1"># Farthest order</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">distances_rank</span><span class="p">:</span> <span class="c1"># From the farthest point</span> + <span class="k">if</span> <span class="n">i</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">selected_ids</span><span class="p">:</span> <span class="c1"># if not selected yes, select it</span> + <span class="n">selected_ids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> + <span class="k">break</span> + <span class="k">return</span> <span class="n">orig_points</span><span class="p">[</span><span class="n">selected_ids</span><span class="p">,</span> <span class="p">:]</span></div> + + +<div class="viewcode-block" id="poisson_disk_sampling"><a class="viewcode-back" href="../../../modules/mapping/point_cloud_sampling/point_cloud_sampling.html#Mapping.point_cloud_sampling.point_cloud_sampling.poisson_disk_sampling">[docs]</a><span class="k">def</span> <span class="nf">poisson_disk_sampling</span><span class="p">(</span><span class="n">orig_points</span><span class="p">:</span> <span class="n">npt</span><span class="o">.</span><span class="n">NDArray</span><span class="p">,</span> <span class="n">n_points</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> + <span class="n">min_distance</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">seed</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">MAX_ITER</span><span class="o">=</span><span class="mi">1000</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Poisson disk sampling function</span> +<span class="sd"> This function sample N-dimensional points randomly until the number of</span> +<span class="sd"> points keeping minimum distance between selected points.</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> orig_points : (M, N) N-dimensional points for sampling.</span> +<span class="sd"> The number of points is M.</span> +<span class="sd"> n_points : number of points for sampling</span> +<span class="sd"> min_distance : minimum distance between selected points.</span> +<span class="sd"> seed : random seed number</span> +<span class="sd"> MAX_ITER : Maximum number of iteration. Default is 1000.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> sampled points (n_points or less, N)</span> +<span class="sd"> """</span> + <span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span> + <span class="n">selected_id</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">orig_points</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span> + <span class="n">selected_ids</span> <span class="o">=</span> <span class="p">[</span><span class="n">selected_id</span><span class="p">]</span> + <span class="n">loop</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">selected_ids</span><span class="p">)</span> <span class="o"><</span> <span class="n">n_points</span> <span class="ow">and</span> <span class="n">loop</span> <span class="o"><=</span> <span class="n">MAX_ITER</span><span class="p">:</span> + <span class="n">selected_id</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">orig_points</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span> + <span class="n">base_point</span> <span class="o">=</span> <span class="n">orig_points</span><span class="p">[</span><span class="n">selected_id</span><span class="p">,</span> <span class="p">:]</span> + <span class="n">distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span> + <span class="n">orig_points</span><span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">newaxis</span><span class="p">,</span> <span class="n">selected_ids</span><span class="p">]</span> <span class="o">-</span> <span class="n">base_point</span><span class="p">,</span> + <span class="n">axis</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span> + <span class="k">if</span> <span class="nb">min</span><span class="p">(</span><span class="n">distances</span><span class="p">)</span> <span class="o">>=</span> <span class="n">min_distance</span><span class="p">:</span> + <span class="n">selected_ids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">selected_id</span><span class="p">)</span> + <span class="n">loop</span> <span class="o">+=</span> <span class="mi">1</span> + <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">selected_ids</span><span class="p">)</span> <span class="o">!=</span> <span class="n">n_points</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"Could not find the specified number of points..."</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">orig_points</span><span class="p">[</span><span class="n">selected_ids</span><span class="p">,</span> <span class="p">:]</span></div> + + +<span class="k">def</span> <span class="nf">plot_sampled_points</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> <span class="n">sampled_points</span><span class="p">,</span> <span class="n">method_name</span><span class="p">):</span> + <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> + <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">projection</span><span class="o">=</span><span class="s1">'3d'</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">original_points</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">original_points</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span> + <span class="n">original_points</span><span class="p">[:,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="s2">"."</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Original points"</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">sampled_points</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">sampled_points</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span> + <span class="n">sampled_points</span><span class="p">[:,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="s2">"o"</span><span class="p">,</span> + <span class="n">label</span><span class="o">=</span><span class="s2">"Filtered points"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="n">method_name</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + <span class="n">n_points</span> <span class="o">=</span> <span class="mi">1000</span> + <span class="n">seed</span> <span class="o">=</span> <span class="mi">1234</span> + <span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span> + + <span class="n">x</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">,</span> <span class="n">n_points</span><span class="p">)</span> + <span class="n">y</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="n">n_points</span><span class="p">)</span> + <span class="n">z</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">,</span> <span class="n">n_points</span><span class="p">)</span> + <span class="n">original_points</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">))</span><span class="o">.</span><span class="n">T</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">original_points</span><span class="o">.</span><span class="n">shape</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"Voxel point sampling"</span><span class="p">)</span> + <span class="n">voxel_size</span> <span class="o">=</span> <span class="mf">20.0</span> + <span class="n">voxel_sampling_points</span> <span class="o">=</span> <span class="n">voxel_point_sampling</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> <span class="n">voxel_size</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">voxel_sampling_points</span><span class="o">.</span><span class="n">shape</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + + <span class="nb">print</span><span class="p">(</span><span class="s2">"Farthest point sampling"</span><span class="p">)</span> + <span class="n">n_points</span> <span class="o">=</span> <span class="mi">20</span> + <span class="n">farthest_sampling_points</span> <span class="o">=</span> <span class="n">farthest_point_sampling</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> + <span class="n">n_points</span><span class="p">,</span> <span class="n">seed</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">farthest_sampling_points</span><span class="o">.</span><span class="n">shape</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + + <span class="nb">print</span><span class="p">(</span><span class="s2">"Poisson disk sampling"</span><span class="p">)</span> + <span class="n">n_points</span> <span class="o">=</span> <span class="mi">20</span> + <span class="n">min_distance</span> <span class="o">=</span> <span class="mf">10.0</span> + <span class="n">poisson_disk_points</span> <span class="o">=</span> <span class="n">poisson_disk_sampling</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> <span class="n">n_points</span><span class="p">,</span> + <span class="n">min_distance</span><span class="p">,</span> <span class="n">seed</span><span class="p">)</span> + <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">poisson_disk_points</span><span class="o">.</span><span class="n">shape</span><span class="si">=}</span><span class="s2">"</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">do_plot</span><span class="p">:</span> + <span class="n">plot_sampled_points</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> <span class="n">voxel_sampling_points</span><span class="p">,</span> + <span class="s2">"Voxel point sampling"</span><span class="p">)</span> + <span class="n">plot_sampled_points</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> <span class="n">farthest_sampling_points</span><span class="p">,</span> + <span class="s2">"Farthest point sampling"</span><span class="p">)</span> + <span class="n">plot_sampled_points</span><span class="p">(</span><span class="n">original_points</span><span class="p">,</span> <span class="n">poisson_disk_points</span><span class="p">,</span> + <span class="s2">"poisson disk sampling"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="n">main</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/Mapping/rectangle_fitting/rectangle_fitting.html b/_modules/Mapping/rectangle_fitting/rectangle_fitting.html new file mode 100644 index 00000000000..d2aa0724a7a --- /dev/null +++ b/_modules/Mapping/rectangle_fitting/rectangle_fitting.html @@ -0,0 +1,424 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Mapping.rectangle_fitting.rectangle_fitting — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>Mapping.rectangle_fitting.rectangle_fitting</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for Mapping.rectangle_fitting.rectangle_fitting</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> + +<span class="sd">Object shape recognition with L-shape fitting</span> + +<span class="sd">author: Atsushi Sakai (@Atsushi_twi)</span> + +<span class="sd">Ref:</span> +<span class="sd">- Efficient L-Shape Fitting for Vehicle Detection Using Laser Scanners -</span> +<span class="sd">The Robotics Institute Carnegie Mellon University</span> +<span class="sd">https://www.ri.cmu.edu/publications/</span> +<span class="sd">efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners/</span> + +<span class="sd">"""</span> + +<span class="kn">import</span> <span class="nn">sys</span> +<span class="kn">import</span> <span class="nn">pathlib</span> +<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span><span class="p">))</span> + +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">itertools</span> +<span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span> + +<span class="kn">from</span> <span class="nn">utils.angle</span> <span class="kn">import</span> <span class="n">rot_mat_2d</span> + +<span class="kn">from</span> <span class="nn">Mapping.rectangle_fitting.simulator</span> \ + <span class="kn">import</span> <span class="nn">VehicleSimulator</span><span class="o">,</span> <span class="nn">LidarSimulator</span> + +<span class="n">show_animation</span> <span class="o">=</span> <span class="kc">True</span> + + +<div class="viewcode-block" id="LShapeFitting"><a class="viewcode-back" href="../../../modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting">[docs]</a><span class="k">class</span> <span class="nc">LShapeFitting</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> LShapeFitting class. You can use this class by initializing the class and</span> +<span class="sd"> changing the parameters, and then calling the fitting method.</span> + +<span class="sd"> """</span> + +<div class="viewcode-block" id="LShapeFitting.Criteria"><a class="viewcode-back" href="../../../modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Criteria">[docs]</a> <span class="k">class</span> <span class="nc">Criteria</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span> + <span class="n">AREA</span> <span class="o">=</span> <span class="mi">1</span> + <span class="n">CLOSENESS</span> <span class="o">=</span> <span class="mi">2</span> + <span class="n">VARIANCE</span> <span class="o">=</span> <span class="mi">3</span></div> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Default parameter settings</span> +<span class="sd"> """</span> + <span class="c1">#: Fitting criteria parameter</span> + <span class="bp">self</span><span class="o">.</span><span class="n">criteria</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Criteria</span><span class="o">.</span><span class="n">VARIANCE</span> + <span class="c1">#: Minimum distance for closeness criteria parameter [m]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">min_dist_of_closeness_criteria</span> <span class="o">=</span> <span class="mf">0.01</span> + <span class="c1">#: Angle difference parameter [deg]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">d_theta_deg_for_search</span> <span class="o">=</span> <span class="mf">1.0</span> + <span class="c1">#: Range segmentation parameter [m]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">R0</span> <span class="o">=</span> <span class="mf">3.0</span> + <span class="c1">#: Range segmentation parameter [m]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">Rd</span> <span class="o">=</span> <span class="mf">0.001</span> + +<div class="viewcode-block" id="LShapeFitting.fitting"><a class="viewcode-back" href="../../../modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.fitting">[docs]</a> <span class="k">def</span> <span class="nf">fitting</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Fitting L-shape model to object points</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> ox : x positions of range points from an object</span> +<span class="sd"> oy : y positions of range points from an object</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> rects: Fitting rectangles</span> +<span class="sd"> id_sets: id sets of each cluster</span> + +<span class="sd"> """</span> + <span class="c1"># step1: Adaptive Range Segmentation</span> + <span class="n">id_sets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adoptive_range_segmentation</span><span class="p">(</span><span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">)</span> + + <span class="c1"># step2 Rectangle search</span> + <span class="n">rects</span> <span class="o">=</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">ids</span> <span class="ow">in</span> <span class="n">id_sets</span><span class="p">:</span> <span class="c1"># for each cluster</span> + <span class="n">cx</span> <span class="o">=</span> <span class="p">[</span><span class="n">ox</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ids</span><span class="p">]</span> + <span class="n">cy</span> <span class="o">=</span> <span class="p">[</span><span class="n">oy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">oy</span><span class="p">))</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ids</span><span class="p">]</span> + <span class="n">rects</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_rectangle_search</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">))</span> + + <span class="k">return</span> <span class="n">rects</span><span class="p">,</span> <span class="n">id_sets</span></div> + + <span class="nd">@staticmethod</span> + <span class="k">def</span> <span class="nf">_calc_area_criterion</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">):</span> + <span class="n">c1_max</span><span class="p">,</span> <span class="n">c1_min</span><span class="p">,</span> <span class="n">c2_max</span><span class="p">,</span> <span class="n">c2_min</span> <span class="o">=</span> <span class="n">LShapeFitting</span><span class="o">.</span><span class="n">_find_min_max</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> + <span class="n">alpha</span> <span class="o">=</span> <span class="o">-</span><span class="p">(</span><span class="n">c1_max</span> <span class="o">-</span> <span class="n">c1_min</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">c2_max</span> <span class="o">-</span> <span class="n">c2_min</span><span class="p">)</span> + <span class="k">return</span> <span class="n">alpha</span> + + <span class="k">def</span> <span class="nf">_calc_closeness_criterion</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">):</span> + <span class="n">c1_max</span><span class="p">,</span> <span class="n">c1_min</span><span class="p">,</span> <span class="n">c2_max</span><span class="p">,</span> <span class="n">c2_min</span> <span class="o">=</span> <span class="n">LShapeFitting</span><span class="o">.</span><span class="n">_find_min_max</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> + + <span class="c1"># Vectorization</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">minimum</span><span class="p">(</span><span class="n">c1_max</span> <span class="o">-</span> <span class="n">c1</span><span class="p">,</span> <span class="n">c1</span> <span class="o">-</span> <span class="n">c1_min</span><span class="p">)</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">minimum</span><span class="p">(</span><span class="n">c2_max</span> <span class="o">-</span> <span class="n">c2</span><span class="p">,</span> <span class="n">c2</span> <span class="o">-</span> <span class="n">c2_min</span><span class="p">)</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">maximum</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">minimum</span><span class="p">(</span><span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">min_dist_of_closeness_criteria</span><span class="p">)</span> + <span class="n">beta</span> <span class="o">=</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">/</span> <span class="n">d</span><span class="p">)</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span> + + <span class="k">return</span> <span class="n">beta</span> + + <span class="nd">@staticmethod</span> + <span class="k">def</span> <span class="nf">_calc_variance_criterion</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">):</span> + <span class="n">c1_max</span><span class="p">,</span> <span class="n">c1_min</span><span class="p">,</span> <span class="n">c2_max</span><span class="p">,</span> <span class="n">c2_min</span> <span class="o">=</span> <span class="n">LShapeFitting</span><span class="o">.</span><span class="n">_find_min_max</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> + + <span class="c1"># Vectorization</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">minimum</span><span class="p">(</span><span class="n">c1_max</span> <span class="o">-</span> <span class="n">c1</span><span class="p">,</span> <span class="n">c1</span> <span class="o">-</span> <span class="n">c1_min</span><span class="p">)</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">minimum</span><span class="p">(</span><span class="n">c2_max</span> <span class="o">-</span> <span class="n">c2</span><span class="p">,</span> <span class="n">c2</span> <span class="o">-</span> <span class="n">c2_min</span><span class="p">)</span> + <span class="n">e1</span> <span class="o">=</span> <span class="n">d1</span><span class="p">[</span><span class="n">d1</span> <span class="o"><</span> <span class="n">d2</span><span class="p">]</span> + <span class="n">e2</span> <span class="o">=</span> <span class="n">d2</span><span class="p">[</span><span class="n">d1</span> <span class="o">>=</span> <span class="n">d2</span><span class="p">]</span> + <span class="n">v1</span> <span class="o">=</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">var</span><span class="p">(</span><span class="n">e1</span><span class="p">)</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">e1</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span> <span class="k">else</span> <span class="mf">0.</span> + <span class="n">v2</span> <span class="o">=</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">var</span><span class="p">(</span><span class="n">e2</span><span class="p">)</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">e2</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span> <span class="k">else</span> <span class="mf">0.</span> + <span class="n">gamma</span> <span class="o">=</span> <span class="n">v1</span> <span class="o">+</span> <span class="n">v2</span> + + <span class="k">return</span> <span class="n">gamma</span> + + <span class="nd">@staticmethod</span> + <span class="k">def</span> <span class="nf">_find_min_max</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">):</span> + <span class="n">c1_max</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span> + <span class="n">c2_max</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">c2</span><span class="p">)</span> + <span class="n">c1_min</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span> + <span class="n">c2_min</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">c2</span><span class="p">)</span> + <span class="k">return</span> <span class="n">c1_max</span><span class="p">,</span> <span class="n">c1_min</span><span class="p">,</span> <span class="n">c2_max</span><span class="p">,</span> <span class="n">c2_min</span> + + <span class="k">def</span> <span class="nf">_rectangle_search</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> + + <span class="n">xy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">])</span><span class="o">.</span><span class="n">T</span> + + <span class="n">d_theta</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">d_theta_deg_for_search</span><span class="p">)</span> + <span class="n">min_cost</span> <span class="o">=</span> <span class="p">(</span><span class="o">-</span><span class="nb">float</span><span class="p">(</span><span class="s1">'inf'</span><span class="p">),</span> <span class="kc">None</span><span class="p">)</span> + <span class="k">for</span> <span class="n">theta</span> <span class="ow">in</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mf">2.0</span> <span class="o">-</span> <span class="n">d_theta</span><span class="p">,</span> <span class="n">d_theta</span><span class="p">):</span> + + <span class="n">c</span> <span class="o">=</span> <span class="n">xy</span> <span class="o">@</span> <span class="n">rot_mat_2d</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> + <span class="n">c1</span> <span class="o">=</span> <span class="n">c</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">c2</span> <span class="o">=</span> <span class="n">c</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">]</span> + + <span class="c1"># Select criteria</span> + <span class="n">cost</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">criteria</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">Criteria</span><span class="o">.</span><span class="n">AREA</span><span class="p">:</span> + <span class="n">cost</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calc_area_criterion</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> + <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">criteria</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">Criteria</span><span class="o">.</span><span class="n">CLOSENESS</span><span class="p">:</span> + <span class="n">cost</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calc_closeness_criterion</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> + <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">criteria</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">Criteria</span><span class="o">.</span><span class="n">VARIANCE</span><span class="p">:</span> + <span class="n">cost</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_calc_variance_criterion</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">min_cost</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o"><</span> <span class="n">cost</span><span class="p">:</span> + <span class="n">min_cost</span> <span class="o">=</span> <span class="p">(</span><span class="n">cost</span><span class="p">,</span> <span class="n">theta</span><span class="p">)</span> + + <span class="c1"># calc best rectangle</span> + <span class="n">sin_s</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">min_cost</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="n">cos_s</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">min_cost</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + + <span class="n">c1_s</span> <span class="o">=</span> <span class="n">xy</span> <span class="o">@</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">cos_s</span><span class="p">,</span> <span class="n">sin_s</span><span class="p">])</span><span class="o">.</span><span class="n">T</span> + <span class="n">c2_s</span> <span class="o">=</span> <span class="n">xy</span> <span class="o">@</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">-</span><span class="n">sin_s</span><span class="p">,</span> <span class="n">cos_s</span><span class="p">])</span><span class="o">.</span><span class="n">T</span> + + <span class="n">rect</span> <span class="o">=</span> <span class="n">RectangleData</span><span class="p">()</span> + <span class="n">rect</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">cos_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">sin_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">c1_s</span><span class="p">)</span> + <span class="n">rect</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="n">sin_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">cos_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">c2_s</span><span class="p">)</span> + <span class="n">rect</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">cos_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">sin_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">c1_s</span><span class="p">)</span> + <span class="n">rect</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="n">sin_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">cos_s</span> + <span class="n">rect</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">c2_s</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">rect</span> + + <span class="k">def</span> <span class="nf">_adoptive_range_segmentation</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">):</span> + + <span class="c1"># Setup initial cluster</span> + <span class="n">segment_list</span> <span class="o">=</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">ox</span><span class="p">):</span> + <span class="n">c</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span> + <span class="n">r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">R0</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">Rd</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">([</span><span class="n">ox</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">oy</span><span class="p">[</span><span class="n">i</span><span class="p">]])</span> + <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">ox</span><span class="p">):</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hypot</span><span class="p">(</span><span class="n">ox</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">ox</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">oy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">oy</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> + <span class="k">if</span> <span class="n">d</span> <span class="o"><=</span> <span class="n">r</span><span class="p">:</span> + <span class="n">c</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">j</span><span class="p">)</span> + <span class="n">segment_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> + + <span class="c1"># Merge cluster</span> + <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> + <span class="n">no_change</span> <span class="o">=</span> <span class="kc">True</span> + <span class="k">for</span> <span class="p">(</span><span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">permutations</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">segment_list</span><span class="p">)),</span> <span class="mi">2</span><span class="p">)):</span> + <span class="k">if</span> <span class="n">segment_list</span><span class="p">[</span><span class="n">c1</span><span class="p">]</span> <span class="o">&</span> <span class="n">segment_list</span><span class="p">[</span><span class="n">c2</span><span class="p">]:</span> + <span class="n">segment_list</span><span class="p">[</span><span class="n">c1</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">segment_list</span><span class="p">[</span><span class="n">c1</span><span class="p">]</span> <span class="o">|</span> <span class="n">segment_list</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">c2</span><span class="p">))</span> + <span class="n">no_change</span> <span class="o">=</span> <span class="kc">False</span> + <span class="k">break</span> + <span class="k">if</span> <span class="n">no_change</span><span class="p">:</span> + <span class="k">break</span> + + <span class="k">return</span> <span class="n">segment_list</span></div> + + +<span class="k">class</span> <span class="nc">RectangleData</span><span class="p">:</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="mi">4</span> + <span class="bp">self</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="mi">4</span> + <span class="bp">self</span><span class="o">.</span><span class="n">c</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="mi">4</span> + + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="mi">5</span> + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span> <span class="o">=</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="o">*</span> <span class="mi">5</span> + + <span class="k">def</span> <span class="nf">plot</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">calc_rect_contour</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">,</span> <span class="s2">"-r"</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">calc_rect_contour</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">calc_cross_point</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">calc_cross_point</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">3</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">3</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">3</span><span class="p">])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">calc_cross_point</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="mi">4</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="mi">4</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="mi">4</span><span class="p">])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">calc_cross_point</span><span class="p">(</span> + <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect_c_y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + + <span class="nd">@staticmethod</span> + <span class="k">def</span> <span class="nf">calc_cross_point</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span> + <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="o">-</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">b</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="o">-</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">b</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> + <span class="n">y</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="o">-</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="o">-</span><span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">b</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> + <span class="k">return</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> + + +<span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + + <span class="c1"># simulation parameters</span> + <span class="n">sim_time</span> <span class="o">=</span> <span class="mf">30.0</span> <span class="c1"># simulation time</span> + <span class="n">dt</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="c1"># time tick</span> + + <span class="n">angle_resolution</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">3.0</span><span class="p">)</span> <span class="c1"># sensor angle resolution</span> + + <span class="n">v1</span> <span class="o">=</span> <span class="n">VehicleSimulator</span><span class="p">(</span><span class="o">-</span><span class="mf">10.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">90.0</span><span class="p">),</span> + <span class="mf">0.0</span><span class="p">,</span> <span class="mf">50.0</span> <span class="o">/</span> <span class="mf">3.6</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">)</span> + <span class="n">v2</span> <span class="o">=</span> <span class="n">VehicleSimulator</span><span class="p">(</span><span class="mf">20.0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">180.0</span><span class="p">),</span> + <span class="mf">0.0</span><span class="p">,</span> <span class="mf">50.0</span> <span class="o">/</span> <span class="mf">3.6</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">)</span> + + <span class="n">l_shape_fitting</span> <span class="o">=</span> <span class="n">LShapeFitting</span><span class="p">()</span> + <span class="n">lidar_sim</span> <span class="o">=</span> <span class="n">LidarSimulator</span><span class="p">()</span> + + <span class="n">time</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="k">while</span> <span class="n">time</span> <span class="o"><=</span> <span class="n">sim_time</span><span class="p">:</span> + <span class="n">time</span> <span class="o">+=</span> <span class="n">dt</span> + + <span class="n">v1</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span> + <span class="n">v2</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.05</span><span class="p">)</span> + + <span class="n">ox</span><span class="p">,</span> <span class="n">oy</span> <span class="o">=</span> <span class="n">lidar_sim</span><span class="o">.</span><span class="n">get_observation_points</span><span class="p">([</span><span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">],</span> <span class="n">angle_resolution</span><span class="p">)</span> + + <span class="n">rects</span><span class="p">,</span> <span class="n">id_sets</span> <span class="o">=</span> <span class="n">l_shape_fitting</span><span class="o">.</span><span class="n">fitting</span><span class="p">(</span><span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">show_animation</span><span class="p">:</span> <span class="c1"># pragma: no cover</span> + <span class="n">plt</span><span class="o">.</span><span class="n">cla</span><span class="p">()</span> + <span class="c1"># for stopping simulation with the esc key.</span> + <span class="n">plt</span><span class="o">.</span><span class="n">gcf</span><span class="p">()</span><span class="o">.</span><span class="n">canvas</span><span class="o">.</span><span class="n">mpl_connect</span><span class="p">(</span> + <span class="s1">'key_release_event'</span><span class="p">,</span> + <span class="k">lambda</span> <span class="n">event</span><span class="p">:</span> <span class="p">[</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'escape'</span> <span class="k">else</span> <span class="kc">None</span><span class="p">])</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="s2">"*r"</span><span class="p">)</span> + <span class="n">v1</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> + <span class="n">v2</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> + + <span class="c1"># Plot range observation</span> + <span class="k">for</span> <span class="n">ids</span> <span class="ow">in</span> <span class="n">id_sets</span><span class="p">:</span> + <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="n">ox</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ids</span><span class="p">]</span> + <span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="n">oy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ids</span><span class="p">]</span> + + <span class="k">for</span> <span class="p">(</span><span class="n">ix</span><span class="p">,</span> <span class="n">iy</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">ix</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">iy</span><span class="p">],</span> <span class="s2">"-og"</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">ox</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ids</span><span class="p">],</span> + <span class="p">[</span><span class="n">oy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ox</span><span class="p">))</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ids</span><span class="p">],</span> + <span class="s2">"o"</span><span class="p">)</span> + <span class="k">for</span> <span class="n">rect</span> <span class="ow">in</span> <span class="n">rects</span><span class="p">:</span> + <span class="n">rect</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">pause</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> + + <span class="nb">print</span><span class="p">(</span><span class="s2">"Done"</span><span class="p">)</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="n">main</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/PathPlanning/BSplinePath/bspline_path.html b/_modules/PathPlanning/BSplinePath/bspline_path.html new file mode 100644 index 00000000000..3725c430746 --- /dev/null +++ b/_modules/PathPlanning/BSplinePath/bspline_path.html @@ -0,0 +1,285 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>PathPlanning.BSplinePath.bspline_path — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>PathPlanning.BSplinePath.bspline_path</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for PathPlanning.BSplinePath.bspline_path</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> + +<span class="sd">Path Planner with B-Spline</span> + +<span class="sd">author: Atsushi Sakai (@Atsushi_twi)</span> + +<span class="sd">"""</span> +<span class="kn">import</span> <span class="nn">sys</span> +<span class="kn">import</span> <span class="nn">pathlib</span> +<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span><span class="p">))</span> + +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">import</span> <span class="nn">scipy.interpolate</span> <span class="k">as</span> <span class="nn">interpolate</span> + +<span class="kn">from</span> <span class="nn">utils.plot</span> <span class="kn">import</span> <span class="n">plot_curvature</span> + + +<div class="viewcode-block" id="approximate_b_spline_path"><a class="viewcode-back" href="../../../modules/path_planning/bspline_path/bspline_path.html#PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path">[docs]</a><span class="k">def</span> <span class="nf">approximate_b_spline_path</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">list</span><span class="p">,</span> + <span class="n">y</span><span class="p">:</span> <span class="nb">list</span><span class="p">,</span> + <span class="n">n_path_points</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> + <span class="n">degree</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> + <span class="n">s</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> + <span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Approximate points with a B-Spline path</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x : array_like</span> +<span class="sd"> x position list of approximated points</span> +<span class="sd"> y : array_like</span> +<span class="sd"> y position list of approximated points</span> +<span class="sd"> n_path_points : int</span> +<span class="sd"> number of path points</span> +<span class="sd"> degree : int, optional</span> +<span class="sd"> B Spline curve degree. Must be 2<= k <= 5. Default: 3.</span> +<span class="sd"> s : int, optional</span> +<span class="sd"> smoothing parameter. If this value is bigger, the path will be</span> +<span class="sd"> smoother, but it will be less accurate. If this value is smaller,</span> +<span class="sd"> the path will be more accurate, but it will be less smooth.</span> +<span class="sd"> When `s` is 0, it is equivalent to the interpolation. Default is None,</span> +<span class="sd"> in this case `s` will be `len(x)`.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> x : array</span> +<span class="sd"> x positions of the result path</span> +<span class="sd"> y : array</span> +<span class="sd"> y positions of the result path</span> +<span class="sd"> heading : array</span> +<span class="sd"> heading of the result path</span> +<span class="sd"> curvature : array</span> +<span class="sd"> curvature of the result path</span> + +<span class="sd"> """</span> + <span class="n">distances</span> <span class="o">=</span> <span class="n">_calc_distance_vector</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> + + <span class="n">spl_i_x</span> <span class="o">=</span> <span class="n">interpolate</span><span class="o">.</span><span class="n">UnivariateSpline</span><span class="p">(</span><span class="n">distances</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="n">degree</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">s</span><span class="p">)</span> + <span class="n">spl_i_y</span> <span class="o">=</span> <span class="n">interpolate</span><span class="o">.</span><span class="n">UnivariateSpline</span><span class="p">(</span><span class="n">distances</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="n">degree</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">s</span><span class="p">)</span> + + <span class="n">sampled</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">distances</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">n_path_points</span><span class="p">)</span> + <span class="k">return</span> <span class="n">_evaluate_spline</span><span class="p">(</span><span class="n">sampled</span><span class="p">,</span> <span class="n">spl_i_x</span><span class="p">,</span> <span class="n">spl_i_y</span><span class="p">)</span></div> + + +<div class="viewcode-block" id="interpolate_b_spline_path"><a class="viewcode-back" href="../../../modules/path_planning/bspline_path/bspline_path.html#PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path">[docs]</a><span class="k">def</span> <span class="nf">interpolate_b_spline_path</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> + <span class="n">n_path_points</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> + <span class="n">degree</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">3</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Interpolate x-y points with a B-Spline path</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x : array_like</span> +<span class="sd"> x positions of interpolated points</span> +<span class="sd"> y : array_like</span> +<span class="sd"> y positions of interpolated points</span> +<span class="sd"> n_path_points : int</span> +<span class="sd"> number of path points</span> +<span class="sd"> degree : int, optional</span> +<span class="sd"> B-Spline degree. Must be 2<= k <= 5. Default: 3</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> x : array</span> +<span class="sd"> x positions of the result path</span> +<span class="sd"> y : array</span> +<span class="sd"> y positions of the result path</span> +<span class="sd"> heading : array</span> +<span class="sd"> heading of the result path</span> +<span class="sd"> curvature : array</span> +<span class="sd"> curvature of the result path</span> + +<span class="sd"> """</span> + <span class="k">return</span> <span class="n">approximate_b_spline_path</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">n_path_points</span><span class="p">,</span> <span class="n">degree</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="mf">0.0</span><span class="p">)</span></div> + + +<span class="k">def</span> <span class="nf">_calc_distance_vector</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> + <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diff</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">diff</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> + <span class="n">distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cumsum</span><span class="p">([</span><span class="n">np</span><span class="o">.</span><span class="n">hypot</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="n">idy</span><span class="p">)</span> <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">idy</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">)])</span> + <span class="n">distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">concatenate</span><span class="p">(([</span><span class="mf">0.0</span><span class="p">],</span> <span class="n">distances</span><span class="p">))</span> + <span class="n">distances</span> <span class="o">/=</span> <span class="n">distances</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> + <span class="k">return</span> <span class="n">distances</span> + + +<span class="k">def</span> <span class="nf">_evaluate_spline</span><span class="p">(</span><span class="n">sampled</span><span class="p">,</span> <span class="n">spl_i_x</span><span class="p">,</span> <span class="n">spl_i_y</span><span class="p">):</span> + <span class="n">x</span> <span class="o">=</span> <span class="n">spl_i_x</span><span class="p">(</span><span class="n">sampled</span><span class="p">)</span> + <span class="n">y</span> <span class="o">=</span> <span class="n">spl_i_y</span><span class="p">(</span><span class="n">sampled</span><span class="p">)</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">spl_i_x</span><span class="o">.</span><span class="n">derivative</span><span class="p">(</span><span class="mi">1</span><span class="p">)(</span><span class="n">sampled</span><span class="p">)</span> + <span class="n">dy</span> <span class="o">=</span> <span class="n">spl_i_y</span><span class="o">.</span><span class="n">derivative</span><span class="p">(</span><span class="mi">1</span><span class="p">)(</span><span class="n">sampled</span><span class="p">)</span> + <span class="n">heading</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arctan2</span><span class="p">(</span><span class="n">dy</span><span class="p">,</span> <span class="n">dx</span><span class="p">)</span> + <span class="n">ddx</span> <span class="o">=</span> <span class="n">spl_i_x</span><span class="o">.</span><span class="n">derivative</span><span class="p">(</span><span class="mi">2</span><span class="p">)(</span><span class="n">sampled</span><span class="p">)</span> + <span class="n">ddy</span> <span class="o">=</span> <span class="n">spl_i_y</span><span class="o">.</span><span class="n">derivative</span><span class="p">(</span><span class="mi">2</span><span class="p">)(</span><span class="n">sampled</span><span class="p">)</span> + <span class="n">curvature</span> <span class="o">=</span> <span class="p">(</span><span class="n">ddy</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">-</span> <span class="n">ddx</span> <span class="o">*</span> <span class="n">dy</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">power</span><span class="p">(</span><span class="n">dx</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">+</span> <span class="n">dy</span> <span class="o">*</span> <span class="n">dy</span><span class="p">,</span> <span class="mf">2.0</span> <span class="o">/</span> <span class="mf">3.0</span><span class="p">)</span> + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">y</span><span class="p">,</span> <span class="n">heading</span><span class="p">,</span> <span class="n">curvature</span><span class="p">,</span> + + +<span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + <span class="nb">print</span><span class="p">(</span><span class="vm">__file__</span> <span class="o">+</span> <span class="s2">" start!!"</span><span class="p">)</span> + <span class="c1"># way points</span> + <span class="n">way_point_x</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]</span> + <span class="n">way_point_y</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">]</span> + <span class="n">n_course_point</span> <span class="o">=</span> <span class="mi">50</span> <span class="c1"># sampling number</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">()</span> + <span class="n">rax</span><span class="p">,</span> <span class="n">ray</span><span class="p">,</span> <span class="n">heading</span><span class="p">,</span> <span class="n">curvature</span> <span class="o">=</span> <span class="n">approximate_b_spline_path</span><span class="p">(</span> + <span class="n">way_point_x</span><span class="p">,</span> <span class="n">way_point_y</span><span class="p">,</span> <span class="n">n_course_point</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">rax</span><span class="p">,</span> <span class="n">ray</span><span class="p">,</span> <span class="s1">'-r'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Approximated B-Spline path"</span><span class="p">)</span> + <span class="n">plot_curvature</span><span class="p">(</span><span class="n">rax</span><span class="p">,</span> <span class="n">ray</span><span class="p">,</span> <span class="n">heading</span><span class="p">,</span> <span class="n">curvature</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"B-Spline approximation"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">way_point_x</span><span class="p">,</span> <span class="n">way_point_y</span><span class="p">,</span> <span class="s1">'-og'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"way points"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">()</span> + <span class="n">rix</span><span class="p">,</span> <span class="n">riy</span><span class="p">,</span> <span class="n">heading</span><span class="p">,</span> <span class="n">curvature</span> <span class="o">=</span> <span class="n">interpolate_b_spline_path</span><span class="p">(</span> + <span class="n">way_point_x</span><span class="p">,</span> <span class="n">way_point_y</span><span class="p">,</span> <span class="n">n_course_point</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">rix</span><span class="p">,</span> <span class="n">riy</span><span class="p">,</span> <span class="s1">'-b'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Interpolated B-Spline path"</span><span class="p">)</span> + <span class="n">plot_curvature</span><span class="p">(</span><span class="n">rix</span><span class="p">,</span> <span class="n">riy</span><span class="p">,</span> <span class="n">heading</span><span class="p">,</span> <span class="n">curvature</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"B-Spline interpolation"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">way_point_x</span><span class="p">,</span> <span class="n">way_point_y</span><span class="p">,</span> <span class="s1">'-og'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"way points"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="n">main</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/PathPlanning/CubicSpline/cubic_spline_planner.html b/_modules/PathPlanning/CubicSpline/cubic_spline_planner.html new file mode 100644 index 00000000000..cf2b0df073c --- /dev/null +++ b/_modules/PathPlanning/CubicSpline/cubic_spline_planner.html @@ -0,0 +1,521 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>PathPlanning.CubicSpline.cubic_spline_planner — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>PathPlanning.CubicSpline.cubic_spline_planner</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for PathPlanning.CubicSpline.cubic_spline_planner</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> +<span class="sd">Cubic spline planner</span> + +<span class="sd">Author: Atsushi Sakai(@Atsushi_twi)</span> + +<span class="sd">"""</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">bisect</span> + + +<div class="viewcode-block" id="CubicSpline1D"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D">[docs]</a><span class="k">class</span> <span class="nc">CubicSpline1D</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> 1D Cubic Spline class</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x : list</span> +<span class="sd"> x coordinates for data points. This x coordinates must be</span> +<span class="sd"> sorted</span> +<span class="sd"> in ascending order.</span> +<span class="sd"> y : list</span> +<span class="sd"> y coordinates for data points</span> + +<span class="sd"> Examples</span> +<span class="sd"> --------</span> +<span class="sd"> You can interpolate 1D data points.</span> + +<span class="sd"> >>> import numpy as np</span> +<span class="sd"> >>> import matplotlib.pyplot as plt</span> +<span class="sd"> >>> x = np.arange(5)</span> +<span class="sd"> >>> y = [1.7, -6, 5, 6.5, 0.0]</span> +<span class="sd"> >>> sp = CubicSpline1D(x, y)</span> +<span class="sd"> >>> xi = np.linspace(0.0, 5.0)</span> +<span class="sd"> >>> yi = [sp.calc_position(x) for x in xi]</span> +<span class="sd"> >>> plt.plot(x, y, "xb", label="Data points")</span> +<span class="sd"> >>> plt.plot(xi, yi , "r", label="Cubic spline interpolation")</span> +<span class="sd"> >>> plt.grid(True)</span> +<span class="sd"> >>> plt.legend()</span> +<span class="sd"> >>> plt.show()</span> + +<span class="sd"> .. image:: cubic_spline_1d.png</span> + +<span class="sd"> """</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> + + <span class="n">h</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diff</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="k">if</span> <span class="n">np</span><span class="o">.</span><span class="n">any</span><span class="p">(</span><span class="n">h</span> <span class="o"><</span> <span class="mi">0</span><span class="p">):</span> + <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"x coordinates must be sorted in ascending order"</span><span class="p">)</span> + + <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span> + <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">y</span> + <span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="c1"># dimension of x</span> + + <span class="c1"># calc coefficient a</span> + <span class="bp">self</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="n">iy</span> <span class="k">for</span> <span class="n">iy</span> <span class="ow">in</span> <span class="n">y</span><span class="p">]</span> + + <span class="c1"># calc coefficient c</span> + <span class="n">A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__calc_A</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> + <span class="n">B</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__calc_B</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">c</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">solve</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span> + + <span class="c1"># calc spline coefficient b and d</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span> + <span class="n">d</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="mf">3.0</span> <span class="o">*</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> + <span class="n">b</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> \ + <span class="o">-</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">/</span> <span class="mf">3.0</span> <span class="o">*</span> <span class="p">(</span><span class="mf">2.0</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> + +<div class="viewcode-block" id="CubicSpline1D.calc_position"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_position">[docs]</a> <span class="k">def</span> <span class="nf">calc_position</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calc `y` position for given `x`.</span> + +<span class="sd"> if `x` is outside the data point's `x` range, return None.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> y : float</span> +<span class="sd"> y position for given x.</span> +<span class="sd"> """</span> + <span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">return</span> <span class="kc">None</span> + <span class="k">elif</span> <span class="n">x</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span> + <span class="k">return</span> <span class="kc">None</span> + + <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__search_index</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> + <span class="n">position</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">+</span> \ + <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">**</span> <span class="mf">2.0</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">**</span> <span class="mf">3.0</span> + + <span class="k">return</span> <span class="n">position</span></div> + +<div class="viewcode-block" id="CubicSpline1D.calc_first_derivative"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_first_derivative">[docs]</a> <span class="k">def</span> <span class="nf">calc_first_derivative</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calc first derivative at given x.</span> + +<span class="sd"> if x is outside the input x, return None</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> dy : float</span> +<span class="sd"> first derivative for given x.</span> +<span class="sd"> """</span> + + <span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">return</span> <span class="kc">None</span> + <span class="k">elif</span> <span class="n">x</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span> + <span class="k">return</span> <span class="kc">None</span> + + <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__search_index</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> + <span class="n">dy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">+</span> <span class="mf">3.0</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">**</span> <span class="mf">2.0</span> + <span class="k">return</span> <span class="n">dy</span></div> + +<div class="viewcode-block" id="CubicSpline1D.calc_second_derivative"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_second_derivative">[docs]</a> <span class="k">def</span> <span class="nf">calc_second_derivative</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calc second derivative at given x.</span> + +<span class="sd"> if x is outside the input x, return None</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> ddy : float</span> +<span class="sd"> second derivative for given x.</span> +<span class="sd"> """</span> + + <span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> + <span class="k">return</span> <span class="kc">None</span> + <span class="k">elif</span> <span class="n">x</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span> + <span class="k">return</span> <span class="kc">None</span> + + <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__search_index</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> + <span class="n">ddy</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mf">6.0</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">dx</span> + <span class="k">return</span> <span class="n">ddy</span></div> + + <span class="k">def</span> <span class="nf">__search_index</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> search data segment index</span> +<span class="sd"> """</span> + <span class="k">return</span> <span class="n">bisect</span><span class="o">.</span><span class="n">bisect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span> + + <span class="k">def</span> <span class="nf">__calc_A</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">h</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> calc matrix A for spline coefficient c</span> +<span class="sd"> """</span> + <span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">nx</span><span class="p">))</span> + <span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span> + <span class="k">if</span> <span class="n">i</span> <span class="o">!=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">):</span> + <span class="n">A</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="p">(</span><span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> + <span class="n">A</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> + <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> + + <span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="n">A</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="n">A</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span> + <span class="k">return</span> <span class="n">A</span> + + <span class="k">def</span> <span class="nf">__calc_B</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">a</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> calc matrix B for spline coefficient c</span> +<span class="sd"> """</span> + <span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span><span class="p">)</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">):</span> + <span class="n">B</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">3.0</span> <span class="o">*</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">-</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>\ + <span class="o">-</span> <span class="mf">3.0</span> <span class="o">*</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">/</span> <span class="n">h</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> + <span class="k">return</span> <span class="n">B</span></div> + + +<div class="viewcode-block" id="CubicSpline2D"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D">[docs]</a><span class="k">class</span> <span class="nc">CubicSpline2D</span><span class="p">:</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Cubic CubicSpline2D class</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x : list</span> +<span class="sd"> x coordinates for data points.</span> +<span class="sd"> y : list</span> +<span class="sd"> y coordinates for data points.</span> + +<span class="sd"> Examples</span> +<span class="sd"> --------</span> +<span class="sd"> You can interpolate a 2D data points.</span> + +<span class="sd"> >>> import matplotlib.pyplot as plt</span> +<span class="sd"> >>> x = [-2.5, 0.0, 2.5, 5.0, 7.5, 3.0, -1.0]</span> +<span class="sd"> >>> y = [0.7, -6, 5, 6.5, 0.0, 5.0, -2.0]</span> +<span class="sd"> >>> ds = 0.1 # [m] distance of each interpolated points</span> +<span class="sd"> >>> sp = CubicSpline2D(x, y)</span> +<span class="sd"> >>> s = np.arange(0, sp.s[-1], ds)</span> +<span class="sd"> >>> rx, ry, ryaw, rk = [], [], [], []</span> +<span class="sd"> >>> for i_s in s:</span> +<span class="sd"> ... ix, iy = sp.calc_position(i_s)</span> +<span class="sd"> ... rx.append(ix)</span> +<span class="sd"> ... ry.append(iy)</span> +<span class="sd"> ... ryaw.append(sp.calc_yaw(i_s))</span> +<span class="sd"> ... rk.append(sp.calc_curvature(i_s))</span> +<span class="sd"> >>> plt.subplots(1)</span> +<span class="sd"> >>> plt.plot(x, y, "xb", label="Data points")</span> +<span class="sd"> >>> plt.plot(rx, ry, "-r", label="Cubic spline path")</span> +<span class="sd"> >>> plt.grid(True)</span> +<span class="sd"> >>> plt.axis("equal")</span> +<span class="sd"> >>> plt.xlabel("x[m]")</span> +<span class="sd"> >>> plt.ylabel("y[m]")</span> +<span class="sd"> >>> plt.legend()</span> +<span class="sd"> >>> plt.show()</span> + +<span class="sd"> .. image:: cubic_spline_2d_path.png</span> + +<span class="sd"> >>> plt.subplots(1)</span> +<span class="sd"> >>> plt.plot(s, [np.rad2deg(iyaw) for iyaw in ryaw], "-r", label="yaw")</span> +<span class="sd"> >>> plt.grid(True)</span> +<span class="sd"> >>> plt.legend()</span> +<span class="sd"> >>> plt.xlabel("line length[m]")</span> +<span class="sd"> >>> plt.ylabel("yaw angle[deg]")</span> + +<span class="sd"> .. image:: cubic_spline_2d_yaw.png</span> + +<span class="sd"> >>> plt.subplots(1)</span> +<span class="sd"> >>> plt.plot(s, rk, "-r", label="curvature")</span> +<span class="sd"> >>> plt.grid(True)</span> +<span class="sd"> >>> plt.legend()</span> +<span class="sd"> >>> plt.xlabel("line length[m]")</span> +<span class="sd"> >>> plt.ylabel("curvature [1/m]")</span> + +<span class="sd"> .. image:: cubic_spline_2d_curvature.png</span> +<span class="sd"> """</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__calc_s</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">sx</span> <span class="o">=</span> <span class="n">CubicSpline1D</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">s</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">sy</span> <span class="o">=</span> <span class="n">CubicSpline1D</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">s</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">__calc_s</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diff</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">dy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diff</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">ds</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hypot</span><span class="p">(</span><span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">)</span> + <span class="n">s</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">s</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">cumsum</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ds</span><span class="p">))</span> + <span class="k">return</span> <span class="n">s</span> + +<div class="viewcode-block" id="CubicSpline2D.calc_position"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_position">[docs]</a> <span class="k">def</span> <span class="nf">calc_position</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> calc position</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> s : float</span> +<span class="sd"> distance from the start point. if `s` is outside the data point's</span> +<span class="sd"> range, return None.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> x : float</span> +<span class="sd"> x position for given s.</span> +<span class="sd"> y : float</span> +<span class="sd"> y position for given s.</span> +<span class="sd"> """</span> + <span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sx</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sy</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span></div> + +<div class="viewcode-block" id="CubicSpline2D.calc_curvature"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_curvature">[docs]</a> <span class="k">def</span> <span class="nf">calc_curvature</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> calc curvature</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> s : float</span> +<span class="sd"> distance from the start point. if `s` is outside the data point's</span> +<span class="sd"> range, return None.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> k : float</span> +<span class="sd"> curvature for given s.</span> +<span class="sd"> """</span> + <span class="n">dx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sx</span><span class="o">.</span><span class="n">calc_first_derivative</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">ddx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sx</span><span class="o">.</span><span class="n">calc_second_derivative</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">dy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sy</span><span class="o">.</span><span class="n">calc_first_derivative</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">ddy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sy</span><span class="o">.</span><span class="n">calc_second_derivative</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">k</span> <span class="o">=</span> <span class="p">(</span><span class="n">ddy</span> <span class="o">*</span> <span class="n">dx</span> <span class="o">-</span> <span class="n">ddx</span> <span class="o">*</span> <span class="n">dy</span><span class="p">)</span> <span class="o">/</span> <span class="p">((</span><span class="n">dx</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">dy</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span><span class="o">**</span><span class="p">(</span><span class="mi">3</span> <span class="o">/</span> <span class="mi">2</span><span class="p">))</span> + <span class="k">return</span> <span class="n">k</span></div> + +<div class="viewcode-block" id="CubicSpline2D.calc_yaw"><a class="viewcode-back" href="../../../modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_yaw">[docs]</a> <span class="k">def</span> <span class="nf">calc_yaw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> calc yaw</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> s : float</span> +<span class="sd"> distance from the start point. if `s` is outside the data point's</span> +<span class="sd"> range, return None.</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> yaw : float</span> +<span class="sd"> yaw angle (tangent vector) for given s.</span> +<span class="sd"> """</span> + <span class="n">dx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sx</span><span class="o">.</span><span class="n">calc_first_derivative</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">dy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sy</span><span class="o">.</span><span class="n">calc_first_derivative</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> + <span class="n">yaw</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">atan2</span><span class="p">(</span><span class="n">dy</span><span class="p">,</span> <span class="n">dx</span><span class="p">)</span> + <span class="k">return</span> <span class="n">yaw</span></div></div> + + +<span class="k">def</span> <span class="nf">calc_spline_course</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">ds</span><span class="o">=</span><span class="mf">0.1</span><span class="p">):</span> + <span class="n">sp</span> <span class="o">=</span> <span class="n">CubicSpline2D</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> + <span class="n">s</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sp</span><span class="o">.</span><span class="n">s</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">ds</span><span class="p">))</span> + + <span class="n">rx</span><span class="p">,</span> <span class="n">ry</span><span class="p">,</span> <span class="n">ryaw</span><span class="p">,</span> <span class="n">rk</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">i_s</span> <span class="ow">in</span> <span class="n">s</span><span class="p">:</span> + <span class="n">ix</span><span class="p">,</span> <span class="n">iy</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">i_s</span><span class="p">)</span> + <span class="n">rx</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ix</span><span class="p">)</span> + <span class="n">ry</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">iy</span><span class="p">)</span> + <span class="n">ryaw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_yaw</span><span class="p">(</span><span class="n">i_s</span><span class="p">))</span> + <span class="n">rk</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_curvature</span><span class="p">(</span><span class="n">i_s</span><span class="p">))</span> + + <span class="k">return</span> <span class="n">rx</span><span class="p">,</span> <span class="n">ry</span><span class="p">,</span> <span class="n">ryaw</span><span class="p">,</span> <span class="n">rk</span><span class="p">,</span> <span class="n">s</span> + + +<span class="k">def</span> <span class="nf">main_1d</span><span class="p">():</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"CubicSpline1D test"</span><span class="p">)</span> + <span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> + <span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> + <span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.7</span><span class="p">,</span> <span class="o">-</span><span class="mi">6</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]</span> + <span class="n">sp</span> <span class="o">=</span> <span class="n">CubicSpline1D</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> + <span class="n">xi</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"xb"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Data points"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xi</span><span class="p">,</span> <span class="p">[</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">xi</span><span class="p">],</span> <span class="s2">"r"</span><span class="p">,</span> + <span class="n">label</span><span class="o">=</span><span class="s2">"Cubic spline interpolation"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">def</span> <span class="nf">main_2d</span><span class="p">():</span> <span class="c1"># pragma: no cover</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"CubicSpline1D 2D test"</span><span class="p">)</span> + <span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> + <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">2.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="mf">7.5</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">]</span> + <span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.7</span><span class="p">,</span> <span class="o">-</span><span class="mi">6</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">]</span> + <span class="n">ds</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="c1"># [m] distance of each interpolated points</span> + + <span class="n">sp</span> <span class="o">=</span> <span class="n">CubicSpline2D</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> + <span class="n">s</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sp</span><span class="o">.</span><span class="n">s</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">ds</span><span class="p">)</span> + + <span class="n">rx</span><span class="p">,</span> <span class="n">ry</span><span class="p">,</span> <span class="n">ryaw</span><span class="p">,</span> <span class="n">rk</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">i_s</span> <span class="ow">in</span> <span class="n">s</span><span class="p">:</span> + <span class="n">ix</span><span class="p">,</span> <span class="n">iy</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">i_s</span><span class="p">)</span> + <span class="n">rx</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ix</span><span class="p">)</span> + <span class="n">ry</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">iy</span><span class="p">)</span> + <span class="n">ryaw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_yaw</span><span class="p">(</span><span class="n">i_s</span><span class="p">))</span> + <span class="n">rk</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_curvature</span><span class="p">(</span><span class="n">i_s</span><span class="p">))</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"xb"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Data points"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">rx</span><span class="p">,</span> <span class="n">ry</span><span class="p">,</span> <span class="s2">"-r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Cubic spline path"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"x[m]"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"y[m]"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">rad2deg</span><span class="p">(</span><span class="n">iyaw</span><span class="p">)</span> <span class="k">for</span> <span class="n">iyaw</span> <span class="ow">in</span> <span class="n">ryaw</span><span class="p">],</span> <span class="s2">"-r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"yaw"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"line length[m]"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"yaw angle[deg]"</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">rk</span><span class="p">,</span> <span class="s2">"-r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"curvature"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"line length[m]"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"curvature [1/m]"</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="c1"># main_1d()</span> + <span class="n">main_2d</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/PathPlanning/DubinsPath/dubins_path_planner.html b/_modules/PathPlanning/DubinsPath/dubins_path_planner.html new file mode 100644 index 00000000000..51d0ed396e1 --- /dev/null +++ b/_modules/PathPlanning/DubinsPath/dubins_path_planner.html @@ -0,0 +1,450 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>PathPlanning.DubinsPath.dubins_path_planner — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../../index.html">Module code</a> »</li> + <li>PathPlanning.DubinsPath.dubins_path_planner</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for PathPlanning.DubinsPath.dubins_path_planner</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> + +<span class="sd">Dubins path planner sample code</span> + +<span class="sd">author Atsushi Sakai(@Atsushi_twi)</span> + +<span class="sd">"""</span> +<span class="kn">import</span> <span class="nn">sys</span> +<span class="kn">import</span> <span class="nn">pathlib</span> +<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span><span class="p">))</span> + +<span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">sin</span><span class="p">,</span> <span class="n">cos</span><span class="p">,</span> <span class="n">atan2</span><span class="p">,</span> <span class="n">sqrt</span><span class="p">,</span> <span class="n">acos</span><span class="p">,</span> <span class="n">pi</span><span class="p">,</span> <span class="n">hypot</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">from</span> <span class="nn">utils.angle</span> <span class="kn">import</span> <span class="n">angle_mod</span><span class="p">,</span> <span class="n">rot_mat_2d</span> + +<span class="n">show_animation</span> <span class="o">=</span> <span class="kc">True</span> + + +<div class="viewcode-block" id="plan_dubins_path"><a class="viewcode-back" href="../../../modules/path_planning/dubins_path/dubins_path.html#PathPlanning.DubinsPath.dubins_path_planner.plan_dubins_path">[docs]</a><span class="k">def</span> <span class="nf">plan_dubins_path</span><span class="p">(</span><span class="n">s_x</span><span class="p">,</span> <span class="n">s_y</span><span class="p">,</span> <span class="n">s_yaw</span><span class="p">,</span> <span class="n">g_x</span><span class="p">,</span> <span class="n">g_y</span><span class="p">,</span> <span class="n">g_yaw</span><span class="p">,</span> <span class="n">curvature</span><span class="p">,</span> + <span class="n">step_size</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">selected_types</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Plan dubins path</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> s_x : float</span> +<span class="sd"> x position of the start point [m]</span> +<span class="sd"> s_y : float</span> +<span class="sd"> y position of the start point [m]</span> +<span class="sd"> s_yaw : float</span> +<span class="sd"> yaw angle of the start point [rad]</span> +<span class="sd"> g_x : float</span> +<span class="sd"> x position of the goal point [m]</span> +<span class="sd"> g_y : float</span> +<span class="sd"> y position of the end point [m]</span> +<span class="sd"> g_yaw : float</span> +<span class="sd"> yaw angle of the end point [rad]</span> +<span class="sd"> curvature : float</span> +<span class="sd"> curvature for curve [1/m]</span> +<span class="sd"> step_size : float (optional)</span> +<span class="sd"> step size between two path points [m]. Default is 0.1</span> +<span class="sd"> selected_types : a list of string or None</span> +<span class="sd"> selected path planning types. If None, all types are used for</span> +<span class="sd"> path planning, and minimum path length result is returned.</span> +<span class="sd"> You can select used path plannings types by a string list.</span> +<span class="sd"> e.g.: ["RSL", "RSR"]</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> x_list: array</span> +<span class="sd"> x positions of the path</span> +<span class="sd"> y_list: array</span> +<span class="sd"> y positions of the path</span> +<span class="sd"> yaw_list: array</span> +<span class="sd"> yaw angles of the path</span> +<span class="sd"> modes: array</span> +<span class="sd"> mode list of the path</span> +<span class="sd"> lengths: array</span> +<span class="sd"> arrow_length list of the path segments.</span> + +<span class="sd"> Examples</span> +<span class="sd"> --------</span> +<span class="sd"> You can generate a dubins path.</span> + +<span class="sd"> >>> start_x = 1.0 # [m]</span> +<span class="sd"> >>> start_y = 1.0 # [m]</span> +<span class="sd"> >>> start_yaw = np.deg2rad(45.0) # [rad]</span> +<span class="sd"> >>> end_x = -3.0 # [m]</span> +<span class="sd"> >>> end_y = -3.0 # [m]</span> +<span class="sd"> >>> end_yaw = np.deg2rad(-45.0) # [rad]</span> +<span class="sd"> >>> curvature = 1.0</span> +<span class="sd"> >>> path_x, path_y, path_yaw, mode, _ = plan_dubins_path(</span> +<span class="sd"> start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature)</span> +<span class="sd"> >>> plt.plot(path_x, path_y, label="final course " + "".join(mode))</span> +<span class="sd"> >>> plot_arrow(start_x, start_y, start_yaw)</span> +<span class="sd"> >>> plot_arrow(end_x, end_y, end_yaw)</span> +<span class="sd"> >>> plt.legend()</span> +<span class="sd"> >>> plt.grid(True)</span> +<span class="sd"> >>> plt.axis("equal")</span> +<span class="sd"> >>> plt.show()</span> + +<span class="sd"> .. image:: dubins_path.jpg</span> +<span class="sd"> """</span> + <span class="k">if</span> <span class="n">selected_types</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">planning_funcs</span> <span class="o">=</span> <span class="n">_PATH_TYPE_MAP</span><span class="o">.</span><span class="n">values</span><span class="p">()</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">planning_funcs</span> <span class="o">=</span> <span class="p">[</span><span class="n">_PATH_TYPE_MAP</span><span class="p">[</span><span class="n">ptype</span><span class="p">]</span> <span class="k">for</span> <span class="n">ptype</span> <span class="ow">in</span> <span class="n">selected_types</span><span class="p">]</span> + + <span class="c1"># calculate local goal x, y, yaw</span> + <span class="n">l_rot</span> <span class="o">=</span> <span class="n">rot_mat_2d</span><span class="p">(</span><span class="n">s_yaw</span><span class="p">)</span> + <span class="n">le_xy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">stack</span><span class="p">([</span><span class="n">g_x</span> <span class="o">-</span> <span class="n">s_x</span><span class="p">,</span> <span class="n">g_y</span> <span class="o">-</span> <span class="n">s_y</span><span class="p">])</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">l_rot</span> + <span class="n">local_goal_x</span> <span class="o">=</span> <span class="n">le_xy</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">local_goal_y</span> <span class="o">=</span> <span class="n">le_xy</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> + <span class="n">local_goal_yaw</span> <span class="o">=</span> <span class="n">g_yaw</span> <span class="o">-</span> <span class="n">s_yaw</span> + + <span class="n">lp_x</span><span class="p">,</span> <span class="n">lp_y</span><span class="p">,</span> <span class="n">lp_yaw</span><span class="p">,</span> <span class="n">modes</span><span class="p">,</span> <span class="n">lengths</span> <span class="o">=</span> <span class="n">_dubins_path_planning_from_origin</span><span class="p">(</span> + <span class="n">local_goal_x</span><span class="p">,</span> <span class="n">local_goal_y</span><span class="p">,</span> <span class="n">local_goal_yaw</span><span class="p">,</span> <span class="n">curvature</span><span class="p">,</span> <span class="n">step_size</span><span class="p">,</span> + <span class="n">planning_funcs</span><span class="p">)</span> + + <span class="c1"># Convert a local coordinate path to the global coordinate</span> + <span class="n">rot</span> <span class="o">=</span> <span class="n">rot_mat_2d</span><span class="p">(</span><span class="o">-</span><span class="n">s_yaw</span><span class="p">)</span> + <span class="n">converted_xy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">stack</span><span class="p">([</span><span class="n">lp_x</span><span class="p">,</span> <span class="n">lp_y</span><span class="p">])</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">rot</span> + <span class="n">x_list</span> <span class="o">=</span> <span class="n">converted_xy</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">s_x</span> + <span class="n">y_list</span> <span class="o">=</span> <span class="n">converted_xy</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">s_y</span> + <span class="n">yaw_list</span> <span class="o">=</span> <span class="n">angle_mod</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">lp_yaw</span><span class="p">)</span> <span class="o">+</span> <span class="n">s_yaw</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">yaw_list</span><span class="p">,</span> <span class="n">modes</span><span class="p">,</span> <span class="n">lengths</span></div> + + +<span class="k">def</span> <span class="nf">_mod2pi</span><span class="p">(</span><span class="n">theta</span><span class="p">):</span> + <span class="k">return</span> <span class="n">angle_mod</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">zero_2_2pi</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">):</span> + <span class="n">sin_a</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span> + <span class="n">sin_b</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span> + <span class="n">cos_a</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span> + <span class="n">cos_b</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span> + <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="n">alpha</span> <span class="o">-</span> <span class="n">beta</span><span class="p">)</span> + <span class="k">return</span> <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> + + +<span class="k">def</span> <span class="nf">_LSL</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> + <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">)</span> + <span class="n">mode</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"L"</span><span class="p">,</span> <span class="s2">"S"</span><span class="p">,</span> <span class="s2">"L"</span><span class="p">]</span> + <span class="n">p_squared</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">d</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">-</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">cos_ab</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">d</span> <span class="o">*</span> <span class="p">(</span><span class="n">sin_a</span> <span class="o">-</span> <span class="n">sin_b</span><span class="p">))</span> + <span class="k">if</span> <span class="n">p_squared</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># invalid configuration</span> + <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">mode</span> + <span class="n">tmp</span> <span class="o">=</span> <span class="n">atan2</span><span class="p">((</span><span class="n">cos_b</span> <span class="o">-</span> <span class="n">cos_a</span><span class="p">),</span> <span class="n">d</span> <span class="o">+</span> <span class="n">sin_a</span> <span class="o">-</span> <span class="n">sin_b</span><span class="p">)</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="o">-</span><span class="n">alpha</span> <span class="o">+</span> <span class="n">tmp</span><span class="p">)</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">p_squared</span><span class="p">)</span> + <span class="n">d3</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">beta</span> <span class="o">-</span> <span class="n">tmp</span><span class="p">)</span> + <span class="k">return</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> + + +<span class="k">def</span> <span class="nf">_RSR</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> + <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">)</span> + <span class="n">mode</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"R"</span><span class="p">,</span> <span class="s2">"S"</span><span class="p">,</span> <span class="s2">"R"</span><span class="p">]</span> + <span class="n">p_squared</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">d</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">-</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">cos_ab</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">d</span> <span class="o">*</span> <span class="p">(</span><span class="n">sin_b</span> <span class="o">-</span> <span class="n">sin_a</span><span class="p">))</span> + <span class="k">if</span> <span class="n">p_squared</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span> + <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">mode</span> + <span class="n">tmp</span> <span class="o">=</span> <span class="n">atan2</span><span class="p">((</span><span class="n">cos_a</span> <span class="o">-</span> <span class="n">cos_b</span><span class="p">),</span> <span class="n">d</span> <span class="o">-</span> <span class="n">sin_a</span> <span class="o">+</span> <span class="n">sin_b</span><span class="p">)</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">alpha</span> <span class="o">-</span> <span class="n">tmp</span><span class="p">)</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">p_squared</span><span class="p">)</span> + <span class="n">d3</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="o">-</span><span class="n">beta</span> <span class="o">+</span> <span class="n">tmp</span><span class="p">)</span> + <span class="k">return</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> + + +<span class="k">def</span> <span class="nf">_LSR</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> + <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">)</span> + <span class="n">p_squared</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span> <span class="o">+</span> <span class="n">d</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">cos_ab</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">d</span> <span class="o">*</span> <span class="p">(</span><span class="n">sin_a</span> <span class="o">+</span> <span class="n">sin_b</span><span class="p">))</span> + <span class="n">mode</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"L"</span><span class="p">,</span> <span class="s2">"S"</span><span class="p">,</span> <span class="s2">"R"</span><span class="p">]</span> + <span class="k">if</span> <span class="n">p_squared</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span> + <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">mode</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">p_squared</span><span class="p">)</span> + <span class="n">tmp</span> <span class="o">=</span> <span class="n">atan2</span><span class="p">((</span><span class="o">-</span><span class="n">cos_a</span> <span class="o">-</span> <span class="n">cos_b</span><span class="p">),</span> <span class="p">(</span><span class="n">d</span> <span class="o">+</span> <span class="n">sin_a</span> <span class="o">+</span> <span class="n">sin_b</span><span class="p">))</span> <span class="o">-</span> <span class="n">atan2</span><span class="p">(</span><span class="o">-</span><span class="mf">2.0</span><span class="p">,</span> <span class="n">d1</span><span class="p">)</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="o">-</span><span class="n">alpha</span> <span class="o">+</span> <span class="n">tmp</span><span class="p">)</span> + <span class="n">d3</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="o">-</span><span class="n">_mod2pi</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span> <span class="o">+</span> <span class="n">tmp</span><span class="p">)</span> + <span class="k">return</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> + + +<span class="k">def</span> <span class="nf">_RSL</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> + <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">)</span> + <span class="n">p_squared</span> <span class="o">=</span> <span class="n">d</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">cos_ab</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">d</span> <span class="o">*</span> <span class="p">(</span><span class="n">sin_a</span> <span class="o">+</span> <span class="n">sin_b</span><span class="p">))</span> + <span class="n">mode</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"R"</span><span class="p">,</span> <span class="s2">"S"</span><span class="p">,</span> <span class="s2">"L"</span><span class="p">]</span> + <span class="k">if</span> <span class="n">p_squared</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span> + <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">mode</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">p_squared</span><span class="p">)</span> + <span class="n">tmp</span> <span class="o">=</span> <span class="n">atan2</span><span class="p">((</span><span class="n">cos_a</span> <span class="o">+</span> <span class="n">cos_b</span><span class="p">),</span> <span class="p">(</span><span class="n">d</span> <span class="o">-</span> <span class="n">sin_a</span> <span class="o">-</span> <span class="n">sin_b</span><span class="p">))</span> <span class="o">-</span> <span class="n">atan2</span><span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="n">d1</span><span class="p">)</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">alpha</span> <span class="o">-</span> <span class="n">tmp</span><span class="p">)</span> + <span class="n">d3</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">beta</span> <span class="o">-</span> <span class="n">tmp</span><span class="p">)</span> + <span class="k">return</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> + + +<span class="k">def</span> <span class="nf">_RLR</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> + <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">)</span> + <span class="n">mode</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"R"</span><span class="p">,</span> <span class="s2">"L"</span><span class="p">,</span> <span class="s2">"R"</span><span class="p">]</span> + <span class="n">tmp</span> <span class="o">=</span> <span class="p">(</span><span class="mf">6.0</span> <span class="o">-</span> <span class="n">d</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">cos_ab</span> <span class="o">+</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">d</span> <span class="o">*</span> <span class="p">(</span><span class="n">sin_a</span> <span class="o">-</span> <span class="n">sin_b</span><span class="p">))</span> <span class="o">/</span> <span class="mf">8.0</span> + <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span> <span class="o">></span> <span class="mf">1.0</span><span class="p">:</span> + <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">mode</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">pi</span> <span class="o">-</span> <span class="n">acos</span><span class="p">(</span><span class="n">tmp</span><span class="p">))</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">alpha</span> <span class="o">-</span> <span class="n">atan2</span><span class="p">(</span><span class="n">cos_a</span> <span class="o">-</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">d</span> <span class="o">-</span> <span class="n">sin_a</span> <span class="o">+</span> <span class="n">sin_b</span><span class="p">)</span> <span class="o">+</span> <span class="n">d2</span> <span class="o">/</span> <span class="mf">2.0</span><span class="p">)</span> + <span class="n">d3</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">alpha</span> <span class="o">-</span> <span class="n">beta</span> <span class="o">-</span> <span class="n">d1</span> <span class="o">+</span> <span class="n">d2</span><span class="p">)</span> + <span class="k">return</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> + + +<span class="k">def</span> <span class="nf">_LRL</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span> + <span class="n">sin_a</span><span class="p">,</span> <span class="n">sin_b</span><span class="p">,</span> <span class="n">cos_a</span><span class="p">,</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">cos_ab</span> <span class="o">=</span> <span class="n">_calc_trig_funcs</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">)</span> + <span class="n">mode</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"L"</span><span class="p">,</span> <span class="s2">"R"</span><span class="p">,</span> <span class="s2">"L"</span><span class="p">]</span> + <span class="n">tmp</span> <span class="o">=</span> <span class="p">(</span><span class="mf">6.0</span> <span class="o">-</span> <span class="n">d</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">cos_ab</span> <span class="o">+</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">d</span> <span class="o">*</span> <span class="p">(</span><span class="o">-</span> <span class="n">sin_a</span> <span class="o">+</span> <span class="n">sin_b</span><span class="p">))</span> <span class="o">/</span> <span class="mf">8.0</span> + <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span> <span class="o">></span> <span class="mf">1.0</span><span class="p">:</span> + <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">mode</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">pi</span> <span class="o">-</span> <span class="n">acos</span><span class="p">(</span><span class="n">tmp</span><span class="p">))</span> + <span class="n">d1</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="o">-</span><span class="n">alpha</span> <span class="o">-</span> <span class="n">atan2</span><span class="p">(</span><span class="n">cos_a</span> <span class="o">-</span> <span class="n">cos_b</span><span class="p">,</span> <span class="n">d</span> <span class="o">+</span> <span class="n">sin_a</span> <span class="o">-</span> <span class="n">sin_b</span><span class="p">)</span> <span class="o">+</span> <span class="n">d2</span> <span class="o">/</span> <span class="mf">2.0</span><span class="p">)</span> + <span class="n">d3</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">_mod2pi</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span> <span class="o">-</span> <span class="n">alpha</span> <span class="o">-</span> <span class="n">d1</span> <span class="o">+</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">d2</span><span class="p">))</span> + <span class="k">return</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> + + +<span class="n">_PATH_TYPE_MAP</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"LSL"</span><span class="p">:</span> <span class="n">_LSL</span><span class="p">,</span> <span class="s2">"RSR"</span><span class="p">:</span> <span class="n">_RSR</span><span class="p">,</span> <span class="s2">"LSR"</span><span class="p">:</span> <span class="n">_LSR</span><span class="p">,</span> <span class="s2">"RSL"</span><span class="p">:</span> <span class="n">_RSL</span><span class="p">,</span> + <span class="s2">"RLR"</span><span class="p">:</span> <span class="n">_RLR</span><span class="p">,</span> <span class="s2">"LRL"</span><span class="p">:</span> <span class="n">_LRL</span><span class="p">,</span> <span class="p">}</span> + + +<span class="k">def</span> <span class="nf">_dubins_path_planning_from_origin</span><span class="p">(</span><span class="n">end_x</span><span class="p">,</span> <span class="n">end_y</span><span class="p">,</span> <span class="n">end_yaw</span><span class="p">,</span> <span class="n">curvature</span><span class="p">,</span> + <span class="n">step_size</span><span class="p">,</span> <span class="n">planning_funcs</span><span class="p">):</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">end_x</span> + <span class="n">dy</span> <span class="o">=</span> <span class="n">end_y</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">hypot</span><span class="p">(</span><span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">)</span> <span class="o">*</span> <span class="n">curvature</span> + + <span class="n">theta</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">atan2</span><span class="p">(</span><span class="n">dy</span><span class="p">,</span> <span class="n">dx</span><span class="p">))</span> + <span class="n">alpha</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="o">-</span><span class="n">theta</span><span class="p">)</span> + <span class="n">beta</span> <span class="o">=</span> <span class="n">_mod2pi</span><span class="p">(</span><span class="n">end_yaw</span> <span class="o">-</span> <span class="n">theta</span><span class="p">)</span> + + <span class="n">best_cost</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">"inf"</span><span class="p">)</span> + <span class="n">b_d1</span><span class="p">,</span> <span class="n">b_d2</span><span class="p">,</span> <span class="n">b_d3</span><span class="p">,</span> <span class="n">b_mode</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span> + + <span class="k">for</span> <span class="n">planner</span> <span class="ow">in</span> <span class="n">planning_funcs</span><span class="p">:</span> + <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span> <span class="o">=</span> <span class="n">planner</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">d</span><span class="p">)</span> + <span class="k">if</span> <span class="n">d1</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="k">continue</span> + + <span class="n">cost</span> <span class="o">=</span> <span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">d1</span><span class="p">)</span> <span class="o">+</span> <span class="nb">abs</span><span class="p">(</span><span class="n">d2</span><span class="p">)</span> <span class="o">+</span> <span class="nb">abs</span><span class="p">(</span><span class="n">d3</span><span class="p">))</span> + <span class="k">if</span> <span class="n">best_cost</span> <span class="o">></span> <span class="n">cost</span><span class="p">:</span> <span class="c1"># Select minimum length one.</span> + <span class="n">b_d1</span><span class="p">,</span> <span class="n">b_d2</span><span class="p">,</span> <span class="n">b_d3</span><span class="p">,</span> <span class="n">b_mode</span><span class="p">,</span> <span class="n">best_cost</span> <span class="o">=</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span><span class="p">,</span> <span class="n">d3</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">cost</span> + + <span class="n">lengths</span> <span class="o">=</span> <span class="p">[</span><span class="n">b_d1</span><span class="p">,</span> <span class="n">b_d2</span><span class="p">,</span> <span class="n">b_d3</span><span class="p">]</span> + <span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">yaw_list</span> <span class="o">=</span> <span class="n">_generate_local_course</span><span class="p">(</span><span class="n">lengths</span><span class="p">,</span> <span class="n">b_mode</span><span class="p">,</span> + <span class="n">curvature</span><span class="p">,</span> <span class="n">step_size</span><span class="p">)</span> + + <span class="n">lengths</span> <span class="o">=</span> <span class="p">[</span><span class="n">length</span> <span class="o">/</span> <span class="n">curvature</span> <span class="k">for</span> <span class="n">length</span> <span class="ow">in</span> <span class="n">lengths</span><span class="p">]</span> + + <span class="k">return</span> <span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">yaw_list</span><span class="p">,</span> <span class="n">b_mode</span><span class="p">,</span> <span class="n">lengths</span> + + +<span class="k">def</span> <span class="nf">_interpolate</span><span class="p">(</span><span class="n">length</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">max_curvature</span><span class="p">,</span> <span class="n">origin_x</span><span class="p">,</span> <span class="n">origin_y</span><span class="p">,</span> + <span class="n">origin_yaw</span><span class="p">,</span> <span class="n">path_x</span><span class="p">,</span> <span class="n">path_y</span><span class="p">,</span> <span class="n">path_yaw</span><span class="p">):</span> + <span class="k">if</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">"S"</span><span class="p">:</span> + <span class="n">path_x</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_x</span> <span class="o">+</span> <span class="n">length</span> <span class="o">/</span> <span class="n">max_curvature</span> <span class="o">*</span> <span class="n">cos</span><span class="p">(</span><span class="n">origin_yaw</span><span class="p">))</span> + <span class="n">path_y</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_y</span> <span class="o">+</span> <span class="n">length</span> <span class="o">/</span> <span class="n">max_curvature</span> <span class="o">*</span> <span class="n">sin</span><span class="p">(</span><span class="n">origin_yaw</span><span class="p">))</span> + <span class="n">path_yaw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_yaw</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> <span class="c1"># curve</span> + <span class="n">ldx</span> <span class="o">=</span> <span class="n">sin</span><span class="p">(</span><span class="n">length</span><span class="p">)</span> <span class="o">/</span> <span class="n">max_curvature</span> + <span class="n">ldy</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="k">if</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">"L"</span><span class="p">:</span> <span class="c1"># left turn</span> + <span class="n">ldy</span> <span class="o">=</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">-</span> <span class="n">cos</span><span class="p">(</span><span class="n">length</span><span class="p">))</span> <span class="o">/</span> <span class="n">max_curvature</span> + <span class="k">elif</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">"R"</span><span class="p">:</span> <span class="c1"># right turn</span> + <span class="n">ldy</span> <span class="o">=</span> <span class="p">(</span><span class="mf">1.0</span> <span class="o">-</span> <span class="n">cos</span><span class="p">(</span><span class="n">length</span><span class="p">))</span> <span class="o">/</span> <span class="o">-</span><span class="n">max_curvature</span> + <span class="n">gdx</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="o">-</span><span class="n">origin_yaw</span><span class="p">)</span> <span class="o">*</span> <span class="n">ldx</span> <span class="o">+</span> <span class="n">sin</span><span class="p">(</span><span class="o">-</span><span class="n">origin_yaw</span><span class="p">)</span> <span class="o">*</span> <span class="n">ldy</span> + <span class="n">gdy</span> <span class="o">=</span> <span class="o">-</span><span class="n">sin</span><span class="p">(</span><span class="o">-</span><span class="n">origin_yaw</span><span class="p">)</span> <span class="o">*</span> <span class="n">ldx</span> <span class="o">+</span> <span class="n">cos</span><span class="p">(</span><span class="o">-</span><span class="n">origin_yaw</span><span class="p">)</span> <span class="o">*</span> <span class="n">ldy</span> + <span class="n">path_x</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_x</span> <span class="o">+</span> <span class="n">gdx</span><span class="p">)</span> + <span class="n">path_y</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_y</span> <span class="o">+</span> <span class="n">gdy</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">"L"</span><span class="p">:</span> <span class="c1"># left turn</span> + <span class="n">path_yaw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_yaw</span> <span class="o">+</span> <span class="n">length</span><span class="p">)</span> + <span class="k">elif</span> <span class="n">mode</span> <span class="o">==</span> <span class="s2">"R"</span><span class="p">:</span> <span class="c1"># right turn</span> + <span class="n">path_yaw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">origin_yaw</span> <span class="o">-</span> <span class="n">length</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">path_x</span><span class="p">,</span> <span class="n">path_y</span><span class="p">,</span> <span class="n">path_yaw</span> + + +<span class="k">def</span> <span class="nf">_generate_local_course</span><span class="p">(</span><span class="n">lengths</span><span class="p">,</span> <span class="n">modes</span><span class="p">,</span> <span class="n">max_curvature</span><span class="p">,</span> <span class="n">step_size</span><span class="p">):</span> + <span class="n">p_x</span><span class="p">,</span> <span class="n">p_y</span><span class="p">,</span> <span class="n">p_yaw</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">]</span> + + <span class="k">for</span> <span class="p">(</span><span class="n">mode</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">modes</span><span class="p">,</span> <span class="n">lengths</span><span class="p">):</span> + <span class="k">if</span> <span class="n">length</span> <span class="o">==</span> <span class="mf">0.0</span><span class="p">:</span> + <span class="k">continue</span> + + <span class="c1"># set origin state</span> + <span class="n">origin_x</span><span class="p">,</span> <span class="n">origin_y</span><span class="p">,</span> <span class="n">origin_yaw</span> <span class="o">=</span> <span class="n">p_x</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">p_y</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">p_yaw</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> + + <span class="n">current_length</span> <span class="o">=</span> <span class="n">step_size</span> + <span class="k">while</span> <span class="nb">abs</span><span class="p">(</span><span class="n">current_length</span> <span class="o">+</span> <span class="n">step_size</span><span class="p">)</span> <span class="o"><=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">length</span><span class="p">):</span> + <span class="n">p_x</span><span class="p">,</span> <span class="n">p_y</span><span class="p">,</span> <span class="n">p_yaw</span> <span class="o">=</span> <span class="n">_interpolate</span><span class="p">(</span><span class="n">current_length</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">max_curvature</span><span class="p">,</span> + <span class="n">origin_x</span><span class="p">,</span> <span class="n">origin_y</span><span class="p">,</span> <span class="n">origin_yaw</span><span class="p">,</span> + <span class="n">p_x</span><span class="p">,</span> <span class="n">p_y</span><span class="p">,</span> <span class="n">p_yaw</span><span class="p">)</span> + <span class="n">current_length</span> <span class="o">+=</span> <span class="n">step_size</span> + + <span class="n">p_x</span><span class="p">,</span> <span class="n">p_y</span><span class="p">,</span> <span class="n">p_yaw</span> <span class="o">=</span> <span class="n">_interpolate</span><span class="p">(</span><span class="n">length</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">max_curvature</span><span class="p">,</span> <span class="n">origin_x</span><span class="p">,</span> + <span class="n">origin_y</span><span class="p">,</span> <span class="n">origin_yaw</span><span class="p">,</span> <span class="n">p_x</span><span class="p">,</span> <span class="n">p_y</span><span class="p">,</span> <span class="n">p_yaw</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">p_x</span><span class="p">,</span> <span class="n">p_y</span><span class="p">,</span> <span class="n">p_yaw</span> + + +<span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"Dubins path planner sample start!!"</span><span class="p">)</span> + <span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> + <span class="kn">from</span> <span class="nn">utils.plot</span> <span class="kn">import</span> <span class="n">plot_arrow</span> + + <span class="n">start_x</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1"># [m]</span> + <span class="n">start_y</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1"># [m]</span> + <span class="n">start_yaw</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">45.0</span><span class="p">)</span> <span class="c1"># [rad]</span> + + <span class="n">end_x</span> <span class="o">=</span> <span class="o">-</span><span class="mf">3.0</span> <span class="c1"># [m]</span> + <span class="n">end_y</span> <span class="o">=</span> <span class="o">-</span><span class="mf">3.0</span> <span class="c1"># [m]</span> + <span class="n">end_yaw</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="o">-</span><span class="mf">45.0</span><span class="p">)</span> <span class="c1"># [rad]</span> + + <span class="n">curvature</span> <span class="o">=</span> <span class="mf">1.0</span> + + <span class="n">path_x</span><span class="p">,</span> <span class="n">path_y</span><span class="p">,</span> <span class="n">path_yaw</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">lengths</span> <span class="o">=</span> <span class="n">plan_dubins_path</span><span class="p">(</span><span class="n">start_x</span><span class="p">,</span> + <span class="n">start_y</span><span class="p">,</span> + <span class="n">start_yaw</span><span class="p">,</span> + <span class="n">end_x</span><span class="p">,</span> + <span class="n">end_y</span><span class="p">,</span> + <span class="n">end_yaw</span><span class="p">,</span> + <span class="n">curvature</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">show_animation</span><span class="p">:</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">path_x</span><span class="p">,</span> <span class="n">path_y</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">mode</span><span class="p">))</span> + <span class="n">plot_arrow</span><span class="p">(</span><span class="n">start_x</span><span class="p">,</span> <span class="n">start_y</span><span class="p">,</span> <span class="n">start_yaw</span><span class="p">)</span> + <span class="n">plot_arrow</span><span class="p">(</span><span class="n">end_x</span><span class="p">,</span> <span class="n">end_y</span><span class="p">,</span> <span class="n">end_yaw</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="n">main</span><span class="p">()</span> +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 00000000000..f5dff4f9d3f --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Overview: module code — PythonRobotics documentation</title> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/clipboard.min.js"></script> + <script src="../_static/copybutton.js"></script> + <script src="../_static/dark_mode_js/default_dark.js"></script> + <script src="../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../index.html" class="icon icon-home"> PythonRobotics + <img src="../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home"></a> »</li> + <li>Overview: module code</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>All modules for which code is available</h1> +<ul><li><a href="Mapping/ndt_map/ndt_map.html">Mapping.ndt_map.ndt_map</a></li> +<li><a href="Mapping/normal_vector_estimation/normal_vector_estimation.html">Mapping.normal_vector_estimation.normal_vector_estimation</a></li> +<li><a href="Mapping/point_cloud_sampling/point_cloud_sampling.html">Mapping.point_cloud_sampling.point_cloud_sampling</a></li> +<li><a href="Mapping/rectangle_fitting/rectangle_fitting.html">Mapping.rectangle_fitting.rectangle_fitting</a></li> +<li><a href="PathPlanning/BSplinePath/bspline_path.html">PathPlanning.BSplinePath.bspline_path</a></li> +<li><a href="PathPlanning/CubicSpline/cubic_spline_planner.html">PathPlanning.CubicSpline.cubic_spline_planner</a></li> +<li><a href="PathPlanning/DubinsPath/dubins_path_planner.html">PathPlanning.DubinsPath.dubins_path_planner</a></li> +<li><a href="utils/plot.html">utils.plot</a></li> +</ul> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_modules/utils/plot.html b/_modules/utils/plot.html new file mode 100644 index 00000000000..bae2f2c727f --- /dev/null +++ b/_modules/utils/plot.html @@ -0,0 +1,367 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>utils.plot — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../index.html">Module code</a> »</li> + <li>utils.plot</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <h1>Source code for utils.plot</h1><div class="highlight"><pre> +<span></span><span class="sd">"""</span> +<span class="sd">Matplotlib based plotting utilities</span> +<span class="sd">"""</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">from</span> <span class="nn">mpl_toolkits.mplot3d</span> <span class="kn">import</span> <span class="n">art3d</span> +<span class="kn">from</span> <span class="nn">matplotlib.patches</span> <span class="kn">import</span> <span class="n">FancyArrowPatch</span> +<span class="kn">from</span> <span class="nn">mpl_toolkits.mplot3d.proj3d</span> <span class="kn">import</span> <span class="n">proj_transform</span> +<span class="kn">from</span> <span class="nn">mpl_toolkits.mplot3d</span> <span class="kn">import</span> <span class="n">Axes3D</span> + +<span class="kn">from</span> <span class="nn">utils.angle</span> <span class="kn">import</span> <span class="n">rot_mat_2d</span> + + +<span class="k">def</span> <span class="nf">plot_covariance_ellipse</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">cov</span><span class="p">,</span> <span class="n">chi2</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"-r"</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> This function plots an ellipse that represents a covariance matrix. The ellipse is centered at (x, y) and its shape, size and rotation are determined by the covariance matrix.</span> + +<span class="sd"> Parameters:</span> +<span class="sd"> x : (float) The x-coordinate of the center of the ellipse.</span> +<span class="sd"> y : (float) The y-coordinate of the center of the ellipse.</span> +<span class="sd"> cov : (numpy.ndarray) A 2x2 covariance matrix that determines the shape, size, and rotation of the ellipse.</span> +<span class="sd"> chi2 : (float, optional) A scalar value that scales the ellipse size. This value is typically set based on chi-squared distribution quantiles to achieve certain confidence levels (e.g., 3.0 corresponds to ~95% confidence for a 2D Gaussian). Defaults to 3.0.</span> +<span class="sd"> color : (str, optional) The color and line style of the ellipse plot, following matplotlib conventions. Defaults to "-r" (a red solid line).</span> +<span class="sd"> ax : (matplotlib.axes.Axes, optional) The Axes object to draw the ellipse on. If None (default), a new figure and axes are created.</span> + +<span class="sd"> Returns:</span> +<span class="sd"> None. This function plots the covariance ellipse on the specified axes.</span> +<span class="sd"> """</span> + <span class="n">eig_val</span><span class="p">,</span> <span class="n">eig_vec</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">eig</span><span class="p">(</span><span class="n">cov</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">eig_val</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">>=</span> <span class="n">eig_val</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> + <span class="n">big_ind</span> <span class="o">=</span> <span class="mi">0</span> + <span class="n">small_ind</span> <span class="o">=</span> <span class="mi">1</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">big_ind</span> <span class="o">=</span> <span class="mi">1</span> + <span class="n">small_ind</span> <span class="o">=</span> <span class="mi">0</span> + <span class="n">a</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">chi2</span> <span class="o">*</span> <span class="n">eig_val</span><span class="p">[</span><span class="n">big_ind</span><span class="p">])</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">chi2</span> <span class="o">*</span> <span class="n">eig_val</span><span class="p">[</span><span class="n">small_ind</span><span class="p">])</span> + <span class="n">angle</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">atan2</span><span class="p">(</span><span class="n">eig_vec</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">big_ind</span><span class="p">],</span> <span class="n">eig_vec</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">big_ind</span><span class="p">])</span> + <span class="n">plot_ellipse</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">angle</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="n">ax</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">plot_ellipse</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">angle</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"-r"</span><span class="p">,</span> <span class="n">ax</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> This function plots an ellipse based on the given parameters.</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x : (float) The x-coordinate of the center of the ellipse.</span> +<span class="sd"> y : (float) The y-coordinate of the center of the ellipse.</span> +<span class="sd"> a : (float) The length of the semi-major axis of the ellipse.</span> +<span class="sd"> b : (float) The length of the semi-minor axis of the ellipse.</span> +<span class="sd"> angle : (float) The rotation angle of the ellipse, in radians.</span> +<span class="sd"> color : (str, optional) The color and line style of the ellipse plot, following matplotlib conventions. Defaults to "-r" (a red solid line).</span> +<span class="sd"> ax : (matplotlib.axes.Axes, optional) The Axes object to draw the ellipse on. If None (default), a new figure and axes are created.</span> +<span class="sd"> **kwargs: Additional keyword arguments to pass to plt.plot or ax.plot.</span> + +<span class="sd"> Returns</span> +<span class="sd"> ---------</span> +<span class="sd"> None. This function plots the ellipse based on the specified parameters.</span> +<span class="sd"> """</span> + + <span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span> <span class="o">+</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">)</span> + <span class="n">px</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">it</span><span class="p">)</span> <span class="k">for</span> <span class="n">it</span> <span class="ow">in</span> <span class="n">t</span><span class="p">]</span> + <span class="n">py</span> <span class="o">=</span> <span class="p">[</span><span class="n">b</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">it</span><span class="p">)</span> <span class="k">for</span> <span class="n">it</span> <span class="ow">in</span> <span class="n">t</span><span class="p">]</span> + <span class="n">fx</span> <span class="o">=</span> <span class="n">rot_mat_2d</span><span class="p">(</span><span class="n">angle</span><span class="p">)</span> <span class="o">@</span> <span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">px</span><span class="p">,</span> <span class="n">py</span><span class="p">]))</span> + <span class="n">px</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">fx</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:]</span> <span class="o">+</span> <span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span> + <span class="n">py</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">fx</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:]</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span> + <span class="k">if</span> <span class="n">ax</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">px</span><span class="p">,</span> <span class="n">py</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">px</span><span class="p">,</span> <span class="n">py</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">plot_arrow</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">yaw</span><span class="p">,</span> <span class="n">arrow_length</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> + <span class="n">origin_point_plot_style</span><span class="o">=</span><span class="s2">"xr"</span><span class="p">,</span> + <span class="n">head_width</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">fc</span><span class="o">=</span><span class="s2">"r"</span><span class="p">,</span> <span class="n">ec</span><span class="o">=</span><span class="s2">"k"</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Plot an arrow or arrows based on 2D state (x, y, yaw)</span> + +<span class="sd"> All optional settings of matplotlib.pyplot.arrow can be used.</span> +<span class="sd"> - matplotlib.pyplot.arrow:</span> +<span class="sd"> https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.arrow.html</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x : a float or array_like</span> +<span class="sd"> a value or a list of arrow origin x position.</span> +<span class="sd"> y : a float or array_like</span> +<span class="sd"> a value or a list of arrow origin y position.</span> +<span class="sd"> yaw : a float or array_like</span> +<span class="sd"> a value or a list of arrow yaw angle (orientation).</span> +<span class="sd"> arrow_length : a float (optional)</span> +<span class="sd"> arrow length. default is 1.0</span> +<span class="sd"> origin_point_plot_style : str (optional)</span> +<span class="sd"> origin point plot style. If None, not plotting.</span> +<span class="sd"> head_width : a float (optional)</span> +<span class="sd"> arrow head width. default is 0.1</span> +<span class="sd"> fc : string (optional)</span> +<span class="sd"> face color</span> +<span class="sd"> ec : string (optional)</span> +<span class="sd"> edge color</span> +<span class="sd"> """</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="nb">float</span><span class="p">):</span> + <span class="k">for</span> <span class="p">(</span><span class="n">i_x</span><span class="p">,</span> <span class="n">i_y</span><span class="p">,</span> <span class="n">i_yaw</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">yaw</span><span class="p">):</span> + <span class="n">plot_arrow</span><span class="p">(</span><span class="n">i_x</span><span class="p">,</span> <span class="n">i_y</span><span class="p">,</span> <span class="n">i_yaw</span><span class="p">,</span> <span class="n">head_width</span><span class="o">=</span><span class="n">head_width</span><span class="p">,</span> + <span class="n">fc</span><span class="o">=</span><span class="n">fc</span><span class="p">,</span> <span class="n">ec</span><span class="o">=</span><span class="n">ec</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">plt</span><span class="o">.</span><span class="n">arrow</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> + <span class="n">arrow_length</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">yaw</span><span class="p">),</span> + <span class="n">arrow_length</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">yaw</span><span class="p">),</span> + <span class="n">head_width</span><span class="o">=</span><span class="n">head_width</span><span class="p">,</span> + <span class="n">fc</span><span class="o">=</span><span class="n">fc</span><span class="p">,</span> <span class="n">ec</span><span class="o">=</span><span class="n">ec</span><span class="p">,</span> + <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="k">if</span> <span class="n">origin_point_plot_style</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">origin_point_plot_style</span><span class="p">)</span> + + +<div class="viewcode-block" id="plot_curvature"><a class="viewcode-back" href="../../modules/utils/plot/plot.html#utils.plot.plot_curvature">[docs]</a><span class="k">def</span> <span class="nf">plot_curvature</span><span class="p">(</span><span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">heading_list</span><span class="p">,</span> <span class="n">curvature</span><span class="p">,</span> + <span class="n">k</span><span class="o">=</span><span class="mf">0.01</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="s2">"-c"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Curvature"</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Plot curvature on 2D path. This plot is a line from the original path,</span> +<span class="sd"> the lateral distance from the original path shows curvature magnitude.</span> +<span class="sd"> Left turning shows right side plot, right turning shows left side plot.</span> +<span class="sd"> For straight path, the curvature plot will be on the path, because</span> +<span class="sd"> curvature is 0 on the straight path.</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> x_list : array_like</span> +<span class="sd"> x position list of the path</span> +<span class="sd"> y_list : array_like</span> +<span class="sd"> y position list of the path</span> +<span class="sd"> heading_list : array_like</span> +<span class="sd"> heading list of the path</span> +<span class="sd"> curvature : array_like</span> +<span class="sd"> curvature list of the path</span> +<span class="sd"> k : float</span> +<span class="sd"> curvature scale factor to calculate distance from the original path</span> +<span class="sd"> c : string</span> +<span class="sd"> color of the plot</span> +<span class="sd"> label : string</span> +<span class="sd"> label of the plot</span> +<span class="sd"> """</span> + <span class="n">cx</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="o">+</span> <span class="n">d</span> <span class="o">*</span> <span class="n">k</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">yaw</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mf">2.0</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">yaw</span><span class="p">,</span> <span class="n">d</span> <span class="ow">in</span> + <span class="nb">zip</span><span class="p">(</span><span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">heading_list</span><span class="p">,</span> <span class="n">curvature</span><span class="p">)]</span> + <span class="n">cy</span> <span class="o">=</span> <span class="p">[</span><span class="n">y</span> <span class="o">+</span> <span class="n">d</span> <span class="o">*</span> <span class="n">k</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">yaw</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mf">2.0</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">yaw</span><span class="p">,</span> <span class="n">d</span> <span class="ow">in</span> + <span class="nb">zip</span><span class="p">(</span><span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">heading_list</span><span class="p">,</span> <span class="n">curvature</span><span class="p">)]</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="n">label</span><span class="p">)</span> + <span class="k">for</span> <span class="n">ix</span><span class="p">,</span> <span class="n">iy</span><span class="p">,</span> <span class="n">icx</span><span class="p">,</span> <span class="n">icy</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">,</span> <span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">):</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">ix</span><span class="p">,</span> <span class="n">icx</span><span class="p">],</span> <span class="p">[</span><span class="n">iy</span><span class="p">,</span> <span class="n">icy</span><span class="p">],</span> <span class="n">c</span><span class="p">)</span></div> + + +<span class="k">class</span> <span class="nc">Arrow3D</span><span class="p">(</span><span class="n">FancyArrowPatch</span><span class="p">):</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">dz</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> + <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">_xyz</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">_dxdydz</span> <span class="o">=</span> <span class="p">(</span><span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">dz</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">renderer</span><span class="p">):</span> + <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">z1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_xyz</span> + <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">dz</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dxdydz</span> + <span class="n">x2</span><span class="p">,</span> <span class="n">y2</span><span class="p">,</span> <span class="n">z2</span> <span class="o">=</span> <span class="p">(</span><span class="n">x1</span> <span class="o">+</span> <span class="n">dx</span><span class="p">,</span> <span class="n">y1</span> <span class="o">+</span> <span class="n">dy</span><span class="p">,</span> <span class="n">z1</span> <span class="o">+</span> <span class="n">dz</span><span class="p">)</span> + + <span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">zs</span> <span class="o">=</span> <span class="n">proj_transform</span><span class="p">((</span><span class="n">x1</span><span class="p">,</span> <span class="n">x2</span><span class="p">),</span> <span class="p">(</span><span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">),</span> <span class="p">(</span><span class="n">z1</span><span class="p">,</span> <span class="n">z2</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">M</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">set_positions</span><span class="p">((</span><span class="n">xs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">ys</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="p">(</span><span class="n">xs</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">ys</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> + <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">renderer</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">do_3d_projection</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> + <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">z1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_xyz</span> + <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">dz</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dxdydz</span> + <span class="n">x2</span><span class="p">,</span> <span class="n">y2</span><span class="p">,</span> <span class="n">z2</span> <span class="o">=</span> <span class="p">(</span><span class="n">x1</span> <span class="o">+</span> <span class="n">dx</span><span class="p">,</span> <span class="n">y1</span> <span class="o">+</span> <span class="n">dy</span><span class="p">,</span> <span class="n">z1</span> <span class="o">+</span> <span class="n">dz</span><span class="p">)</span> + + <span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">,</span> <span class="n">zs</span> <span class="o">=</span> <span class="n">proj_transform</span><span class="p">((</span><span class="n">x1</span><span class="p">,</span> <span class="n">x2</span><span class="p">),</span> <span class="p">(</span><span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">),</span> <span class="p">(</span><span class="n">z1</span><span class="p">,</span> <span class="n">z2</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">M</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">set_positions</span><span class="p">((</span><span class="n">xs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">ys</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="p">(</span><span class="n">xs</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">ys</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> + + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">zs</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">_arrow3D</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">dz</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> +<span class="w"> </span><span class="sd">'''Add an 3d arrow to an `Axes3D` instance.'''</span> + <span class="n">arrow</span> <span class="o">=</span> <span class="n">Arrow3D</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">dz</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">add_artist</span><span class="p">(</span><span class="n">arrow</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">plot_3d_vector_arrow</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">):</span> + <span class="nb">setattr</span><span class="p">(</span><span class="n">Axes3D</span><span class="p">,</span> <span class="s1">'arrow3D'</span><span class="p">,</span> <span class="n">_arrow3D</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">arrow3D</span><span class="p">(</span><span class="n">p1</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">p1</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">p1</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> + <span class="n">p2</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">-</span><span class="n">p1</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">p2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">-</span><span class="n">p1</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">p2</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">-</span><span class="n">p1</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> + <span class="n">mutation_scale</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> + <span class="n">arrowstyle</span><span class="o">=</span><span class="s2">"-|>"</span><span class="p">,</span> + <span class="p">)</span> + + +<span class="k">def</span> <span class="nf">plot_triangle</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">,</span> <span class="n">ax</span><span class="p">):</span> + <span class="n">ax</span><span class="o">.</span><span class="n">add_collection3d</span><span class="p">(</span><span class="n">art3d</span><span class="o">.</span><span class="n">Poly3DCollection</span><span class="p">([[</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s1">'b'</span><span class="p">))</span> + + +<span class="k">def</span> <span class="nf">set_equal_3d_axis</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">x_lims</span><span class="p">,</span> <span class="n">y_lims</span><span class="p">,</span> <span class="n">z_lims</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""Helper function to set equal axis</span> + +<span class="sd"> Args:</span> +<span class="sd"> ax (Axes3DSubplot): matplotlib 3D axis, created by</span> +<span class="sd"> `ax = fig.add_subplot(projection='3d')`</span> +<span class="sd"> x_lims (np.array): array containing min and max value of x</span> +<span class="sd"> y_lims (np.array): array containing min and max value of y</span> +<span class="sd"> z_lims (np.array): array containing min and max value of z</span> +<span class="sd"> """</span> + <span class="n">x_lims</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">x_lims</span><span class="p">)</span> + <span class="n">y_lims</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">y_lims</span><span class="p">)</span> + <span class="n">z_lims</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">z_lims</span><span class="p">)</span> + <span class="c1"># compute max required range</span> + <span class="n">max_range</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">x_lims</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">x_lims</span><span class="o">.</span><span class="n">min</span><span class="p">(),</span> + <span class="n">y_lims</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">y_lims</span><span class="o">.</span><span class="n">min</span><span class="p">(),</span> + <span class="n">z_lims</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">z_lims</span><span class="o">.</span><span class="n">min</span><span class="p">()])</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">/</span> <span class="mf">2.0</span> + <span class="c1"># compute mid-point along each axis</span> + <span class="n">mid_x</span> <span class="o">=</span> <span class="p">(</span><span class="n">x_lims</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">+</span> <span class="n">x_lims</span><span class="o">.</span><span class="n">min</span><span class="p">())</span> <span class="o">*</span> <span class="mf">0.5</span> + <span class="n">mid_y</span> <span class="o">=</span> <span class="p">(</span><span class="n">y_lims</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">+</span> <span class="n">y_lims</span><span class="o">.</span><span class="n">min</span><span class="p">())</span> <span class="o">*</span> <span class="mf">0.5</span> + <span class="n">mid_z</span> <span class="o">=</span> <span class="p">(</span><span class="n">z_lims</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">+</span> <span class="n">z_lims</span><span class="o">.</span><span class="n">min</span><span class="p">())</span> <span class="o">*</span> <span class="mf">0.5</span> + + <span class="c1"># set limits to axis</span> + <span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="n">mid_x</span> <span class="o">-</span> <span class="n">max_range</span><span class="p">,</span> <span class="n">mid_x</span> <span class="o">+</span> <span class="n">max_range</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="n">mid_y</span> <span class="o">-</span> <span class="n">max_range</span><span class="p">,</span> <span class="n">mid_y</span> <span class="o">+</span> <span class="n">max_range</span><span class="p">)</span> + <span class="n">ax</span><span class="o">.</span><span class="n">set_zlim</span><span class="p">(</span><span class="n">mid_z</span> <span class="o">-</span> <span class="n">max_range</span><span class="p">,</span> <span class="n">mid_z</span> <span class="o">+</span> <span class="n">max_range</span><span class="p">)</span> + + +<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> + <span class="n">plot_ellipse</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mi">15</span><span class="p">))</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s1">'equal'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + +</pre></div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/_sources/getting_started_main.rst.txt b/_sources/getting_started_main.rst.txt new file mode 100644 index 00000000000..497b85a23a8 --- /dev/null +++ b/_sources/getting_started_main.rst.txt @@ -0,0 +1,85 @@ +.. _`getting started`: + +Getting Started +=============== + +What is this? +------------- + +This is an Open Source Software (OSS) project: PythonRobotics, which is a Python code collection of robotics algorithms. + +The focus of the project is on autonomous navigation, and the goal is for beginners in robotics to understand the basic ideas behind each algorithm. + +In this project, the algorithms which are practical and widely used in both academia and industry are selected. + +Each sample code is written in Python3 and only depends on some standard modules for readability and ease of use. + +It includes intuitive animations to understand the behavior of the simulation. + + +See this paper for more details: + +- PythonRobotics: a Python code collection of robotics algorithms: https://arxiv.org/abs/1808.10703 + +.. _`Requirements`: + +Requirements +------------- + +- `Python 3.11.x`_ +- `NumPy`_ +- `SciPy`_ +- `Matplotlib`_ +- `cvxpy`_ + +For development: + +- `pytest`_ (for unit tests) +- `pytest-xdist`_ (for parallel unit tests) +- `mypy`_ (for type check) +- `sphinx`_ (for document generation) +- `ruff`_ (for code style check) + +.. _`Python 3.11.x`: https://www.python.org/ +.. _`NumPy`: https://numpy.org/ +.. _`SciPy`: https://scipy.org/ +.. _`Matplotlib`: https://matplotlib.org/ +.. _`cvxpy`: https://www.cvxpy.org/ +.. _`pytest`: https://docs.pytest.org/en/latest/ +.. _`pytest-xdist`: https://github.com/pytest-dev/pytest-xdist +.. _`mypy`: https://mypy-lang.org/ +.. _`sphinx`: https://www.sphinx-doc.org/en/master/index.html +.. _`ruff`: https://github.com/charliermarsh/ruff + + +How to use +---------- + +1. Clone this repo and go into dir. + +.. code-block:: + + >$ git clone https://github.com/AtsushiSakai/PythonRobotics.git + + >$ cd PythonRobotics + + +2. Install the required libraries. + +using conda : + +.. code-block:: + + >$ conda env create -f requirements/environment.yml + +using pip : + +.. code-block:: + + >$ pip install -r requirements/requirements.txt + + +3. Execute python script in each directory. + +4. Add star to this repo if you like it 😃. + diff --git a/docs/modules/0_getting_started/3_how_to_contribute_main.rst b/_sources/how_to_contribute_main.rst.txt similarity index 69% rename from docs/modules/0_getting_started/3_how_to_contribute_main.rst rename to _sources/how_to_contribute_main.rst.txt index 1e61760649f..48895d6fdad 100644 --- a/docs/modules/0_getting_started/3_how_to_contribute_main.rst +++ b/_sources/how_to_contribute_main.rst.txt @@ -1,39 +1,10 @@ -How to contribute +How To Contribute ================= This document describes how to contribute this project. -There are several ways to contribute to this project as below: -#. `Adding a new algorithm example`_ -#. `Reporting and fixing a defect`_ -#. `Adding missed documentations for existing examples`_ -#. `Supporting this project`_ - -Before contributing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Please check following items before contributing: - -Understanding this project ---------------------------- - -Please check this :ref:`What is PythonRobotics?` section and this paper -`PythonRobotics: a Python code collection of robotics algorithms`_ -to understand the philosophies of this project. - -.. _`PythonRobotics: a Python code collection of robotics algorithms`: https://arxiv.org/abs/1808.10703 - -Check your Python version. ---------------------------- - -We only accept a PR for Python 3.12.x or higher. - -We will not accept a PR for Python 2.x. - -.. _`Adding a new algorithm example`: - -1. Adding a new algorithm example -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Adding a new algorithm example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is a step by step manual to add a new algorithm example. @@ -96,16 +67,9 @@ Please check other documents for details. You can build the doc locally based on `doc README`_. -For creating a gif animation, you can use this tool: `matplotrecorder`_. - -The created gif file should be stored in the `PythonRoboticsGifs`_ repository, -so please create a PR to add it and refer to it in the doc. - -Note that the `reStructuredText`_ based doc should only focus on the -mathematics and the algorithm of the example. +Note that the `reStructuredText`_ based doc should only focus on the mathematics and the algorithm of the example. -Documentations related codes should be in the python script as the header -comments of the script or docstrings of each function. +Documentations related codes should be in the python script as the header comments of the script or docstrings of each function. .. _`submit a pull request`: @@ -128,12 +92,9 @@ After that, I will start the review. Note that this is my hobby project; I appreciate your patience during the review process. - -.. _`Reporting and fixing a defect`: - -2. Reporting and fixing a defect -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Reporting and fixing a defect +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Reporting and fixing a defect is also great contribution. @@ -154,24 +115,19 @@ in the test code to show the issue was solved. This doc `submit a pull request`_ can be helpful to submit a pull request. -.. _`Adding missed documentations for existing examples`: - -3. Adding missed documentations for existing examples -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Adding missed documentations for existing examples +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Adding the missed documentations for existing examples is also great contribution. If you check the `Python Robotics Docs`_, you can notice that some of the examples -only have a simulation gif or short overview descriptions or just TBD., +only have a simulation gif or short overview descriptions, but no detailed algorithm or mathematical description. -These documents needs to be improved. This doc `how to write doc`_ can be helpful to write documents. -.. _`Supporting this project`: - -4. Supporting this project -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Supporting this project +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Supporting this project financially is also a great contribution!!. @@ -185,12 +141,10 @@ If you or your company would like to support this project, please consider: If you would like to support us in some other way, please contact with creating an issue. -Current Major Sponsors: - -#. `GitHub`_ : They are providing a GitHub Copilot Pro license for this OSS development. -#. `JetBrains`_ : They are providing a free license of their IDEs for this OSS development. -#. `1Password`_ : They are providing a free license of their 1Password team license for this OSS project. +Sponsors +--------- +1. `JetBrains`_ : They are providing a free license of their IDEs for this OSS development. .. _`Python Robotics Docs`: https://atsushisakai.github.io/PythonRobotics @@ -203,12 +157,8 @@ Current Major Sponsors: .. _`doc README`: https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/README.md .. _`test_codestyle.py`: https://github.com/AtsushiSakai/PythonRobotics/blob/master/tests/test_codestyle.py .. _`JetBrains`: https://www.jetbrains.com/ -.. _`GitHub`: https://www.github.com/ .. _`Sponsor @AtsushiSakai on GitHub Sponsors`: https://github.com/sponsors/AtsushiSakai .. _`Become a backer or sponsor on Patreon`: https://www.patreon.com/myenigma -.. _`One-time donation via PayPal`: https://www.paypal.com/paypalme/myenigmapay/ -.. _`1Password`: https://github.com/1Password/for-open-source -.. _`matplotrecorder`: https://github.com/AtsushiSakai/matplotrecorder -.. _`PythonRoboticsGifs`: https://github.com/AtsushiSakai/PythonRoboticsGifs +.. _`One-time donation via PayPal`: https://www.paypal.me/myenigmapay/ diff --git a/_sources/index_main.rst.txt b/_sources/index_main.rst.txt new file mode 100644 index 00000000000..67bd9889f2a --- /dev/null +++ b/_sources/index_main.rst.txt @@ -0,0 +1,57 @@ +.. PythonRobotics documentation master file, created by + sphinx-quickstart on Sat Sep 15 13:15:55 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to PythonRobotics's documentation! +========================================== + +Python codes for robotics algorithm. The project is on `GitHub`_. + +This is a Python code collection of robotics algorithms. + +Features: + +1. Easy to read for understanding each algorithm's basic idea. + +2. Widely used and practical algorithms are selected. + +3. Minimum dependency. + +See this paper for more details: + +- `[1808.10703] PythonRobotics: a Python code collection of robotics + algorithms`_ (`BibTeX`_) + + +.. _`[1808.10703] PythonRobotics: a Python code collection of robotics algorithms`: https://arxiv.org/abs/1808.10703 +.. _BibTeX: https://github.com/AtsushiSakai/PythonRoboticsPaper/blob/master/python_robotics.bib +.. _GitHub: https://github.com/AtsushiSakai/PythonRobotics + + +.. toctree:: + :maxdepth: 2 + :caption: Contents + + getting_started + modules/introduction + modules/localization/localization + modules/mapping/mapping + modules/slam/slam + modules/path_planning/path_planning + modules/path_tracking/path_tracking + modules/arm_navigation/arm_navigation + modules/aerial_navigation/aerial_navigation + modules/bipedal/bipedal + modules/control/control + modules/utils/utils + modules/appendix/appendix + how_to_contribute + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/modules/8_aerial_navigation/aerial_navigation_main.rst b/_sources/modules/aerial_navigation/aerial_navigation_main.rst.txt similarity index 89% rename from docs/modules/8_aerial_navigation/aerial_navigation_main.rst rename to _sources/modules/aerial_navigation/aerial_navigation_main.rst.txt index 7f766897702..b2ccb071aff 100644 --- a/docs/modules/8_aerial_navigation/aerial_navigation_main.rst +++ b/_sources/modules/aerial_navigation/aerial_navigation_main.rst.txt @@ -1,4 +1,4 @@ -.. _`Aerial Navigation`: +.. _aerial_navigation: Aerial Navigation ================= diff --git a/docs/modules/8_aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following_main.rst b/_sources/modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following_main.rst.txt similarity index 100% rename from docs/modules/8_aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following_main.rst rename to _sources/modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following_main.rst.txt diff --git a/docs/modules/8_aerial_navigation/rocket_powered_landing/rocket_powered_landing_main.rst b/_sources/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing_main.rst.txt similarity index 100% rename from docs/modules/8_aerial_navigation/rocket_powered_landing/rocket_powered_landing_main.rst rename to _sources/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing_main.rst.txt diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_2_main.rst b/_sources/modules/appendix/Kalmanfilter_basics_2_main.rst.txt similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_2_main.rst rename to _sources/modules/appendix/Kalmanfilter_basics_2_main.rst.txt diff --git a/docs/modules/12_appendix/Kalmanfilter_basics_main.rst b/_sources/modules/appendix/Kalmanfilter_basics_main.rst.txt similarity index 100% rename from docs/modules/12_appendix/Kalmanfilter_basics_main.rst rename to _sources/modules/appendix/Kalmanfilter_basics_main.rst.txt diff --git a/docs/modules/12_appendix/appendix_main.rst b/_sources/modules/appendix/appendix_main.rst.txt similarity index 61% rename from docs/modules/12_appendix/appendix_main.rst rename to _sources/modules/appendix/appendix_main.rst.txt index d0b9eeea3a8..8a29d846764 100644 --- a/docs/modules/12_appendix/appendix_main.rst +++ b/_sources/modules/appendix/appendix_main.rst.txt @@ -1,4 +1,4 @@ -.. _`Appendix`: +.. _appendix: Appendix ============== @@ -7,9 +7,6 @@ Appendix :maxdepth: 2 :caption: Contents - steering_motion_model Kalmanfilter_basics Kalmanfilter_basics_2 - internal_sensors - external_sensors diff --git a/docs/modules/7_arm_navigation/arm_navigation_main.rst b/_sources/modules/arm_navigation/arm_navigation_main.rst.txt similarity index 88% rename from docs/modules/7_arm_navigation/arm_navigation_main.rst rename to _sources/modules/arm_navigation/arm_navigation_main.rst.txt index 7acd3ee7d39..bbbc872c580 100644 --- a/docs/modules/7_arm_navigation/arm_navigation_main.rst +++ b/_sources/modules/arm_navigation/arm_navigation_main.rst.txt @@ -1,4 +1,4 @@ -.. _`Arm Navigation`: +.. _arm_navigation: Arm Navigation ============== diff --git a/docs/modules/7_arm_navigation/n_joint_arm_to_point_control_main.rst b/_sources/modules/arm_navigation/n_joint_arm_to_point_control_main.rst.txt similarity index 100% rename from docs/modules/7_arm_navigation/n_joint_arm_to_point_control_main.rst rename to _sources/modules/arm_navigation/n_joint_arm_to_point_control_main.rst.txt diff --git a/docs/modules/7_arm_navigation/obstacle_avoidance_arm_navigation_main.rst b/_sources/modules/arm_navigation/obstacle_avoidance_arm_navigation_main.rst.txt similarity index 100% rename from docs/modules/7_arm_navigation/obstacle_avoidance_arm_navigation_main.rst rename to _sources/modules/arm_navigation/obstacle_avoidance_arm_navigation_main.rst.txt diff --git a/docs/modules/7_arm_navigation/planar_two_link_ik_main.rst b/_sources/modules/arm_navigation/planar_two_link_ik_main.rst.txt similarity index 100% rename from docs/modules/7_arm_navigation/planar_two_link_ik_main.rst rename to _sources/modules/arm_navigation/planar_two_link_ik_main.rst.txt diff --git a/docs/modules/9_bipedal/bipedal_main.rst b/_sources/modules/bipedal/bipedal_main.rst.txt similarity index 88% rename from docs/modules/9_bipedal/bipedal_main.rst rename to _sources/modules/bipedal/bipedal_main.rst.txt index dc387dc4e83..fc5b9330559 100644 --- a/docs/modules/9_bipedal/bipedal_main.rst +++ b/_sources/modules/bipedal/bipedal_main.rst.txt @@ -1,4 +1,4 @@ -.. _`Bipedal`: +.. _bipedal: Bipedal ================= diff --git a/docs/modules/9_bipedal/bipedal_planner/bipedal_planner_main.rst b/_sources/modules/bipedal/bipedal_planner/bipedal_planner_main.rst.txt similarity index 100% rename from docs/modules/9_bipedal/bipedal_planner/bipedal_planner_main.rst rename to _sources/modules/bipedal/bipedal_planner/bipedal_planner_main.rst.txt diff --git a/_sources/modules/control/control_main.rst.txt b/_sources/modules/control/control_main.rst.txt new file mode 100644 index 00000000000..cee2aa9e8e4 --- /dev/null +++ b/_sources/modules/control/control_main.rst.txt @@ -0,0 +1,12 @@ +.. _control: + +Control +================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents + + inverted_pendulum_control/inverted_pendulum_control + move_to_a_pose_control/move_to_a_pose_control + diff --git a/docs/modules/10_inverted_pendulum/inverted_pendulum_main.rst b/_sources/modules/control/inverted_pendulum_control/inverted_pendulum_control_main.rst.txt similarity index 97% rename from docs/modules/10_inverted_pendulum/inverted_pendulum_main.rst rename to _sources/modules/control/inverted_pendulum_control/inverted_pendulum_control_main.rst.txt index 048cbea9acd..e41729fd61f 100644 --- a/docs/modules/10_inverted_pendulum/inverted_pendulum_main.rst +++ b/_sources/modules/control/inverted_pendulum_control/inverted_pendulum_control_main.rst.txt @@ -1,7 +1,5 @@ -.. _`Inverted Pendulum`: - -Inverted Pendulum ------------------- +Inverted Pendulum Control +----------------------------- An inverted pendulum on a cart consists of a mass :math:`m` at the top of a pole of length :math:`l` pivoted on a horizontally moving base as shown in the adjacent. diff --git a/docs/modules/6_path_tracking/move_to_a_pose_control/move_to_a_pose_control_main.rst b/_sources/modules/control/move_to_a_pose_control/move_to_a_pose_control_main.rst.txt similarity index 100% rename from docs/modules/6_path_tracking/move_to_a_pose_control/move_to_a_pose_control_main.rst rename to _sources/modules/control/move_to_a_pose_control/move_to_a_pose_control_main.rst.txt diff --git a/_sources/modules/introduction_main.rst.txt b/_sources/modules/introduction_main.rst.txt new file mode 100644 index 00000000000..f9fb487297d --- /dev/null +++ b/_sources/modules/introduction_main.rst.txt @@ -0,0 +1,42 @@ + +Introduction +============ + +TBD + +Definition Of Robotics +---------------------- + +TBD + +History Of Robotics +---------------------- + +TBD + +Application Of Robotics +------------------------ + +TBD + +Software for Robotics +---------------------- + +TBD + +Software for Robotics +---------------------- + +TBD + +Python for Robotics +---------------------- + +TBD + +Learning Robotics Algorithms +---------------------------- + +TBD + + diff --git a/docs/modules/2_localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization_main.rst b/_sources/modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization_main.rst.txt similarity index 100% rename from docs/modules/2_localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization_main.rst rename to _sources/modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization_main.rst.txt diff --git a/docs/modules/2_localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst b/_sources/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst.txt similarity index 51% rename from docs/modules/2_localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst rename to _sources/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst.txt index da214b6de58..0ec920c9dfa 100644 --- a/docs/modules/2_localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst +++ b/_sources/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst.txt @@ -2,9 +2,6 @@ Extended Kalman Filter Localization ----------------------------------- -Position Estimation Kalman Filter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. image:: extended_kalman_filter_localization_1_0.png :width: 600px @@ -12,7 +9,6 @@ Position Estimation Kalman Filter .. figure:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/extended_kalman_filter/animation.gif - This is a sensor fusion localization with Extended Kalman Filter(EKF). The blue line is true trajectory, the black line is dead reckoning @@ -26,26 +22,9 @@ The red ellipse is estimated covariance ellipse with EKF. Code: `PythonRobotics/extended_kalman_filter.py at master · AtsushiSakai/PythonRobotics <https://github.com/AtsushiSakai/PythonRobotics/blob/master/Localization/extended_kalman_filter/extended_kalman_filter.py>`__ -Kalman Filter with Speed Scale Factor Correction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - -.. image:: ekf_with_velocity_correction_1_0.png - :width: 600px - -This is a Extended kalman filter (EKF) localization with velocity correction. - -This is for correcting the vehicle speed measured with scale factor errors due to factors such as wheel wear. - -Code: `PythonRobotics/extended_kalman_ekf_with_velocity_correctionfilter.py -AtsushiSakai/PythonRobotics <https://github.com/AtsushiSakai/PythonRobotics/blob/master/Localization/extended_kalman_filter/extended_kalman_ekf_with_velocity_correctionfilter.py>`__ - Filter design ~~~~~~~~~~~~~ -Position Estimation Kalman Filter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - In this simulation, the robot has a state vector includes 4 states at time :math:`t`. @@ -82,28 +61,9 @@ In the code, “observation” function generates the input and observation vector with noise `code <https://github.com/AtsushiSakai/PythonRobotics/blob/916b4382de090de29f54538b356cef1c811aacce/Localization/extended_kalman_filter/extended_kalman_filter.py#L34-L50>`__ -Kalman Filter with Speed Scale Factor Correction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In this simulation, the robot has a state vector includes 5 states at -time :math:`t`. - -.. math:: \textbf{x}_t=[x_t, y_t, \phi_t, v_t, s_t] - -x, y are a 2D x-y position, :math:`\phi` is orientation, v is -velocity, and s is a scale factor of velocity. - -In the code, “xEst” means the state vector. -`code <https://github.com/AtsushiSakai/PythonRobotics/blob/916b4382de090de29f54538b356cef1c811aacce/Localization/extended_kalman_filter/extended_kalman_ekf_with_velocity_correctionfilter.py#L163>`__ - -The rest is the same as the Position Estimation Kalman Filter. - Motion Model ~~~~~~~~~~~~ -Position Estimation Kalman Filter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The robot model is .. math:: \dot{x} = v \cos(\phi) @@ -137,50 +97,9 @@ Its Jacobian matrix is :math:`\begin{equation*} = \begin{bmatrix} 1& 0 & -v \sin(\phi) \Delta t & \cos(\phi) \Delta t\\ 0 & 1 & v \cos(\phi) \Delta t & \sin(\phi) \Delta t\\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \end{equation*}` - -Kalman Filter with Speed Scale Factor Correction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The robot model is - -.. math:: \dot{x} = v s \cos(\phi) - -.. math:: \dot{y} = v s \sin(\phi) - -.. math:: \dot{\phi} = \omega - -So, the motion model is - -.. math:: \textbf{x}_{t+1} = f(\textbf{x}_t, \textbf{u}_t) = F\textbf{x}_t+B\textbf{u}_t - -where - -:math:`\begin{equation*} F= \begin{bmatrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 & 1\\ \end{bmatrix} \end{equation*}` - -:math:`\begin{equation*} B= \begin{bmatrix} cos(\phi) \Delta t s & 0\\ sin(\phi) \Delta t s & 0\\ 0 & \Delta t\\ 1 & 0\\ 0 & 0\\ \end{bmatrix} \end{equation*}` - -:math:`\Delta t` is a time interval. - -This is implemented at -`code <https://github.com/AtsushiSakai/PythonRobotics/blob/916b4382de090de29f54538b356cef1c811aacce/Localization/extended_kalman_filter/extended_kalman_filter.py#L61-L76>`__ - -The motion function is that - -:math:`\begin{equation*} \begin{bmatrix} x' \\ y' \\ w' \\ v' \end{bmatrix} = f(\textbf{x}, \textbf{u}) = \begin{bmatrix} x + v s \cos(\phi)\Delta t \\ y + v s \sin(\phi)\Delta t \\ \phi + \omega \Delta t \\ v \end{bmatrix} \end{equation*}` - -Its Jacobian matrix is - -:math:`\begin{equation*} J_f = \begin{bmatrix} \frac{\partial x'}{\partial x}& \frac{\partial x'}{\partial y} & \frac{\partial x'}{\partial \phi} & \frac{\partial x'}{\partial v} & \frac{\partial x'}{\partial s}\\ \frac{\partial y'}{\partial x}& \frac{\partial y'}{\partial y} & \frac{\partial y'}{\partial \phi} & \frac{\partial y'}{\partial v} & \frac{\partial y'}{\partial s}\\ \frac{\partial \phi'}{\partial x}& \frac{\partial \phi'}{\partial y} & \frac{\partial \phi'}{\partial \phi} & \frac{\partial \phi'}{\partial v} & \frac{\partial \phi'}{\partial s}\\ \frac{\partial v'}{\partial x}& \frac{\partial v'}{\partial y} & \frac{\partial v'}{\partial \phi} & \frac{\partial v'}{\partial v} & \frac{\partial v'}{\partial s} \\ \frac{\partial s'}{\partial x}& \frac{\partial s'}{\partial y} & \frac{\partial s'}{\partial \phi} & \frac{\partial s'}{\partial v} & \frac{\partial s'}{\partial s} \end{bmatrix} \end{equation*}` - -:math:`\begin{equation*} = \begin{bmatrix} 1& 0 & -v s \sin(\phi) \Delta t & s \cos(\phi) \Delta t & \cos(\phi) v \Delta t\\ 0 & 1 & v s \cos(\phi) \Delta t & s \sin(\phi) \Delta t & v \sin(\phi) \Delta t\\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \end{bmatrix} \end{equation*}` - - Observation Model ~~~~~~~~~~~~~~~~~ -Position Estimation Kalman Filter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The robot can get x-y position infomation from GPS. So GPS Observation model is @@ -201,30 +120,6 @@ Its Jacobian matrix is :math:`\begin{equation*} = \begin{bmatrix} 1& 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ \end{bmatrix} \end{equation*}` -Kalman Filter with Speed Scale Factor Correction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The robot can get x-y position infomation from GPS. - -So GPS Observation model is - -.. math:: \textbf{z}_{t} = g(\textbf{x}_t) = H \textbf{x}_t - -where - -:math:`\begin{equation*} H = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ \end{bmatrix} \end{equation*}` - -The observation function states that - -:math:`\begin{equation*} \begin{bmatrix} x' \\ y' \end{bmatrix} = g(\textbf{x}) = \begin{bmatrix} x \\ y \end{bmatrix} \end{equation*}` - -Its Jacobian matrix is - -:math:`\begin{equation*} J_g = \begin{bmatrix} \frac{\partial x'}{\partial x} & \frac{\partial x'}{\partial y} & \frac{\partial x'}{\partial \phi} & \frac{\partial x'}{\partial v} & \frac{\partial x'}{\partial s}\\ \frac{\partial y'}{\partial x}& \frac{\partial y'}{\partial y} & \frac{\partial y'}{\partial \phi} & \frac{\partial y'}{ \partial v} & \frac{\partial y'}{ \partial s}\\ \end{bmatrix} \end{equation*}` - -:math:`\begin{equation*} = \begin{bmatrix} 1& 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0\\ \end{bmatrix} \end{equation*}` - - Extended Kalman Filter ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/modules/2_localization/histogram_filter_localization/histogram_filter_localization_main.rst b/_sources/modules/localization/histogram_filter_localization/histogram_filter_localization_main.rst.txt similarity index 100% rename from docs/modules/2_localization/histogram_filter_localization/histogram_filter_localization_main.rst rename to _sources/modules/localization/histogram_filter_localization/histogram_filter_localization_main.rst.txt diff --git a/docs/modules/2_localization/localization_main.rst b/_sources/modules/localization/localization_main.rst.txt similarity index 55% rename from docs/modules/2_localization/localization_main.rst rename to _sources/modules/localization/localization_main.rst.txt index 770a234b69e..db6651f6b87 100644 --- a/docs/modules/2_localization/localization_main.rst +++ b/_sources/modules/localization/localization_main.rst.txt @@ -1,8 +1,7 @@ -.. _`Localization`: +.. _localization: Localization ============ -Localization is the ability of a robot to know its position and orientation with sensors such as Global Navigation Satellite System:GNSS etc. In localization, Bayesian filters such as Kalman filters, histogram filter, and particle filter are widely used[31]. Fig.2 shows localization simulations using histogram filter and particle filter. .. toctree:: :maxdepth: 2 diff --git a/docs/modules/2_localization/particle_filter_localization/particle_filter_localization_main.rst b/_sources/modules/localization/particle_filter_localization/particle_filter_localization_main.rst.txt similarity index 94% rename from docs/modules/2_localization/particle_filter_localization/particle_filter_localization_main.rst rename to _sources/modules/localization/particle_filter_localization/particle_filter_localization_main.rst.txt index 20a9eb58fc3..c8652ce8a75 100644 --- a/docs/modules/2_localization/particle_filter_localization/particle_filter_localization_main.rst +++ b/_sources/modules/localization/particle_filter_localization/particle_filter_localization_main.rst.txt @@ -34,4 +34,4 @@ References: ~~~~~~~~~~~ - `_PROBABILISTIC ROBOTICS: <http://www.probabilistic-robotics.org>`_ -- `Improving the particle filter in high dimensions using conjugate artificial process noise <https://arxiv.org/pdf/1801.07000>`_ +- `Improving the particle filter in high dimensions using conjugate artificial process noise <https://arxiv.org/pdf/1801.07000.pdf>`_ diff --git a/docs/modules/2_localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization_main.rst b/_sources/modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization_main.rst.txt similarity index 100% rename from docs/modules/2_localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization_main.rst rename to _sources/modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization_main.rst.txt diff --git a/docs/modules/3_mapping/circle_fitting/circle_fitting_main.rst b/_sources/modules/mapping/circle_fitting/circle_fitting_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/circle_fitting/circle_fitting_main.rst rename to _sources/modules/mapping/circle_fitting/circle_fitting_main.rst.txt diff --git a/docs/modules/3_mapping/gaussian_grid_map/gaussian_grid_map_main.rst b/_sources/modules/mapping/gaussian_grid_map/gaussian_grid_map_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/gaussian_grid_map/gaussian_grid_map_main.rst rename to _sources/modules/mapping/gaussian_grid_map/gaussian_grid_map_main.rst.txt diff --git a/docs/modules/3_mapping/k_means_object_clustering/k_means_object_clustering_main.rst b/_sources/modules/mapping/k_means_object_clustering/k_means_object_clustering_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/k_means_object_clustering/k_means_object_clustering_main.rst rename to _sources/modules/mapping/k_means_object_clustering/k_means_object_clustering_main.rst.txt diff --git a/docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_main.rst b/_sources/modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_main.rst rename to _sources/modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_main.rst.txt diff --git a/docs/modules/3_mapping/mapping_main.rst b/_sources/modules/mapping/mapping_main.rst.txt similarity index 50% rename from docs/modules/3_mapping/mapping_main.rst rename to _sources/modules/mapping/mapping_main.rst.txt index 34a37448936..a98acaaf503 100644 --- a/docs/modules/3_mapping/mapping_main.rst +++ b/_sources/modules/mapping/mapping_main.rst.txt @@ -1,9 +1,7 @@ -.. _`Mapping`: +.. _mapping: Mapping ======= -Mapping is the ability of a robot to understand its surroundings with external sensors such as LIDAR and camera. Robots have to recognize the position and shape of obstacles to avoid them. In mapping, grid mapping and machine learning algorithms are widely used[31][18]. Fig.3 shows mapping simulation results using grid mapping with 2D ray casting and 2D object clustering with k-means algorithm. - .. toctree:: :maxdepth: 2 :caption: Contents @@ -17,4 +15,3 @@ Mapping is the ability of a robot to understand its surroundings with external s circle_fitting/circle_fitting rectangle_fitting/rectangle_fitting normal_vector_estimation/normal_vector_estimation - distance_map/distance_map diff --git a/docs/modules/3_mapping/ndt_map/ndt_map_main.rst b/_sources/modules/mapping/ndt_map/ndt_map_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/ndt_map/ndt_map_main.rst rename to _sources/modules/mapping/ndt_map/ndt_map_main.rst.txt diff --git a/docs/modules/3_mapping/normal_vector_estimation/normal_vector_estimation_main.rst b/_sources/modules/mapping/normal_vector_estimation/normal_vector_estimation_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/normal_vector_estimation/normal_vector_estimation_main.rst rename to _sources/modules/mapping/normal_vector_estimation/normal_vector_estimation_main.rst.txt diff --git a/docs/modules/3_mapping/point_cloud_sampling/point_cloud_sampling_main.rst b/_sources/modules/mapping/point_cloud_sampling/point_cloud_sampling_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/point_cloud_sampling/point_cloud_sampling_main.rst rename to _sources/modules/mapping/point_cloud_sampling/point_cloud_sampling_main.rst.txt diff --git a/docs/modules/3_mapping/ray_casting_grid_map/ray_casting_grid_map_main.rst b/_sources/modules/mapping/ray_casting_grid_map/ray_casting_grid_map_main.rst.txt similarity index 100% rename from docs/modules/3_mapping/ray_casting_grid_map/ray_casting_grid_map_main.rst rename to _sources/modules/mapping/ray_casting_grid_map/ray_casting_grid_map_main.rst.txt diff --git a/docs/modules/3_mapping/rectangle_fitting/rectangle_fitting_main.rst b/_sources/modules/mapping/rectangle_fitting/rectangle_fitting_main.rst.txt similarity index 97% rename from docs/modules/3_mapping/rectangle_fitting/rectangle_fitting_main.rst rename to _sources/modules/mapping/rectangle_fitting/rectangle_fitting_main.rst.txt index b6ced1dc1d7..50a50141b29 100644 --- a/docs/modules/3_mapping/rectangle_fitting/rectangle_fitting_main.rst +++ b/_sources/modules/mapping/rectangle_fitting/rectangle_fitting_main.rst.txt @@ -7,7 +7,7 @@ This is an object shape recognition using rectangle fitting. This example code is based on this paper algorithm: -- `Efficient L\-Shape Fitting for Vehicle Detection Using Laser Scanners \- The Robotics Institute Carnegie Mellon University <https://www.ri.cmu.edu/publications/efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners/>`_ +- `Efficient L\-Shape Fitting for Vehicle Detection Using Laser Scanners \- The Robotics Institute Carnegie Mellon University <https://www.ri.cmu.edu/publications/efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners>`_ The algorithm consists of 2 steps as below. @@ -66,4 +66,4 @@ API References ~~~~~~~~~~ -- `Efficient L\-Shape Fitting for Vehicle Detection Using Laser Scanners \- The Robotics Institute Carnegie Mellon University <https://www.ri.cmu.edu/publications/efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners/>`_ +- `Efficient L\-Shape Fitting for Vehicle Detection Using Laser Scanners \- The Robotics Institute Carnegie Mellon University <https://www.ri.cmu.edu/publications/efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners>`_ diff --git a/docs/modules/5_path_planning/bezier_path/bezier_path_main.rst b/_sources/modules/path_planning/bezier_path/bezier_path_main.rst.txt similarity index 75% rename from docs/modules/5_path_planning/bezier_path/bezier_path_main.rst rename to _sources/modules/path_planning/bezier_path/bezier_path_main.rst.txt index d306a853525..fbba6a4496b 100644 --- a/docs/modules/5_path_planning/bezier_path/bezier_path_main.rst +++ b/_sources/modules/path_planning/bezier_path/bezier_path_main.rst.txt @@ -17,4 +17,4 @@ Ref: - `Continuous Curvature Path Generation Based on Bezier Curves for Autonomous - Vehicles <https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=b00b657c3e0e828c589132a14825e7119772003d>` + Vehicles <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.294.6438&rep=rep1&type=pdf>`__ diff --git a/docs/modules/5_path_planning/bspline_path/bspline_path_main.rst b/_sources/modules/path_planning/bspline_path/bspline_path_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/bspline_path/bspline_path_main.rst rename to _sources/modules/path_planning/bspline_path/bspline_path_main.rst.txt diff --git a/docs/modules/5_path_planning/bugplanner/bugplanner_main.rst b/_sources/modules/path_planning/bugplanner/bugplanner_main.rst.txt similarity index 59% rename from docs/modules/5_path_planning/bugplanner/bugplanner_main.rst rename to _sources/modules/path_planning/bugplanner/bugplanner_main.rst.txt index 81c91c0313e..72cc46709f7 100644 --- a/docs/modules/5_path_planning/bugplanner/bugplanner_main.rst +++ b/_sources/modules/path_planning/bugplanner/bugplanner_main.rst.txt @@ -5,4 +5,4 @@ This is a 2D planning with Bug algorithm. .. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BugPlanner/animation.gif -- `ECE452 Bug Algorithms <https://web.archive.org/web/20201103052224/https://sites.google.com/site/ece452bugalgorithms/>`_ +- `ECE452 Bug Algorithms <https://sites.google.com/site/ece452bugalgorithms/>`_ diff --git a/docs/modules/5_path_planning/clothoid_path/clothoid_path_main.rst b/_sources/modules/path_planning/clothoid_path/clothoid_path_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/clothoid_path/clothoid_path_main.rst rename to _sources/modules/path_planning/clothoid_path/clothoid_path_main.rst.txt diff --git a/docs/modules/5_path_planning/coverage_path/coverage_path_main.rst b/_sources/modules/path_planning/coverage_path/coverage_path_main.rst.txt similarity index 93% rename from docs/modules/5_path_planning/coverage_path/coverage_path_main.rst rename to _sources/modules/path_planning/coverage_path/coverage_path_main.rst.txt index 0a688b5ed27..828342a294c 100644 --- a/docs/modules/5_path_planning/coverage_path/coverage_path_main.rst +++ b/_sources/modules/path_planning/coverage_path/coverage_path_main.rst.txt @@ -29,6 +29,6 @@ This is a 2D grid based wavefront coverage path planner simulation: .. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation2.gif .. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation3.gif -- `Planning paths of complete coverage of an unstructured environment by a mobile robot <https://pinkwink.kr/attachment/cfile3.uf@1354654A4E8945BD13FE77.pdf>`_ +- `Planning paths of complete coverage of an unstructured environment by a mobile robot <http://pinkwink.kr/attachment/cfile3.uf@1354654A4E8945BD13FE77.pdf>`_ diff --git a/docs/modules/5_path_planning/cubic_spline/cubic_spline_main.rst b/_sources/modules/path_planning/cubic_spline/cubic_spline_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/cubic_spline/cubic_spline_main.rst rename to _sources/modules/path_planning/cubic_spline/cubic_spline_main.rst.txt diff --git a/docs/modules/5_path_planning/dubins_path/dubins_path_main.rst b/_sources/modules/path_planning/dubins_path/dubins_path_main.rst.txt similarity index 97% rename from docs/modules/5_path_planning/dubins_path/dubins_path_main.rst rename to _sources/modules/path_planning/dubins_path/dubins_path_main.rst.txt index 12172fb51e1..516638d83da 100644 --- a/docs/modules/5_path_planning/dubins_path/dubins_path_main.rst +++ b/_sources/modules/path_planning/dubins_path/dubins_path_main.rst.txt @@ -72,5 +72,5 @@ Reference ~~~~~~~~~~~~~~~~~~~~ - `On Curves of Minimal Length with a Constraint on Average Curvature, and with Prescribed Initial and Terminal Positions and Tangents <https://www.jstor.org/stable/2372560?origin=crossref>`__ - `Dubins path - Wikipedia <https://en.wikipedia.org/wiki/Dubins_path>`__ -- `15.3.1 Dubins Curves <https://lavalle.pl/planning/node821.html>`__ +- `15.3.1 Dubins Curves <http://planning.cs.uiuc.edu/node821.html>`__ - `A Comprehensive, Step-by-Step Tutorial to Computing Dubin’s Paths <https://gieseanw.wordpress.com/2012/10/21/a-comprehensive-step-by-step-tutorial-to-computing-dubins-paths/>`__ diff --git a/docs/modules/5_path_planning/dynamic_window_approach/dynamic_window_approach_main.rst b/_sources/modules/path_planning/dynamic_window_approach/dynamic_window_approach_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/dynamic_window_approach/dynamic_window_approach_main.rst rename to _sources/modules/path_planning/dynamic_window_approach/dynamic_window_approach_main.rst.txt diff --git a/docs/modules/5_path_planning/eta3_spline/eta3_spline_main.rst b/_sources/modules/path_planning/eta3_spline/eta3_spline_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/eta3_spline/eta3_spline_main.rst rename to _sources/modules/path_planning/eta3_spline/eta3_spline_main.rst.txt diff --git a/_sources/modules/path_planning/frenet_frame_path/frenet_frame_path_main.rst.txt b/_sources/modules/path_planning/frenet_frame_path/frenet_frame_path_main.rst.txt new file mode 100644 index 00000000000..e9d9041e0e4 --- /dev/null +++ b/_sources/modules/path_planning/frenet_frame_path/frenet_frame_path_main.rst.txt @@ -0,0 +1,20 @@ +Optimal Trajectory in a Frenet Frame +------------------------------------ + +.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/animation.gif + +This is optimal trajectory generation in a Frenet Frame. + +The cyan line is the target course and black crosses are obstacles. + +The red line is predicted path. + +Ref: + +- `Optimal Trajectory Generation for Dynamic Street Scenarios in a + Frenet + Frame <https://www.researchgate.net/profile/Moritz_Werling/publication/224156269_Optimal_Trajectory_Generation_for_Dynamic_Street_Scenarios_in_a_Frenet_Frame/links/54f749df0cf210398e9277af.pdf>`__ + +- `Optimal trajectory generation for dynamic street scenarios in a + Frenet Frame <https://www.youtube.com/watch?v=Cj6tAQe7UCY>`__ + diff --git a/docs/modules/5_path_planning/grid_base_search/grid_base_search_main.rst b/_sources/modules/path_planning/grid_base_search/grid_base_search_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/grid_base_search/grid_base_search_main.rst rename to _sources/modules/path_planning/grid_base_search/grid_base_search_main.rst.txt diff --git a/docs/modules/5_path_planning/hybridastar/hybridastar_main.rst b/_sources/modules/path_planning/hybridastar/hybridastar_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/hybridastar/hybridastar_main.rst rename to _sources/modules/path_planning/hybridastar/hybridastar_main.rst.txt diff --git a/docs/modules/5_path_planning/lqr_path/lqr_path_main.rst b/_sources/modules/path_planning/lqr_path/lqr_path_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/lqr_path/lqr_path_main.rst rename to _sources/modules/path_planning/lqr_path/lqr_path_main.rst.txt diff --git a/docs/modules/5_path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst b/_sources/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst.txt similarity index 87% rename from docs/modules/5_path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst rename to _sources/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst.txt index 463363ddcf1..0fc997898ed 100644 --- a/docs/modules/5_path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst +++ b/_sources/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst.txt @@ -19,4 +19,4 @@ Lookup table generation sample Ref: - `Optimal rough terrain trajectory generation for wheeled mobile - robots <https://journals.sagepub.com/doi/pdf/10.1177/0278364906075328>`__ + robots <http://journals.sagepub.com/doi/pdf/10.1177/0278364906075328>`__ diff --git a/docs/modules/5_path_planning/path_planning_main.rst b/_sources/modules/path_planning/path_planning_main.rst.txt similarity index 57% rename from docs/modules/5_path_planning/path_planning_main.rst rename to _sources/modules/path_planning/path_planning_main.rst.txt index 0c84a19c22f..a3237f16f19 100644 --- a/docs/modules/5_path_planning/path_planning_main.rst +++ b/_sources/modules/path_planning/path_planning_main.rst.txt @@ -1,10 +1,8 @@ -.. _`Path Planning`: +.. _path_planning: Path Planning ============= -Path planning is the ability of a robot to search feasible and efficient path to the goal. The path has to satisfy some constraints based on the robot’s motion model and obstacle positions, and optimize some objective functions such as time to goal and distance to obstacle. In path planning, dynamic programming based approaches and sampling based approaches are widely used[22]. Fig.5 shows simulation results of potential field path planning and LQRRRT* path planning[27]. - .. toctree:: :maxdepth: 2 :caption: Contents @@ -12,7 +10,6 @@ Path planning is the ability of a robot to search feasible and efficient path to dynamic_window_approach/dynamic_window_approach bugplanner/bugplanner grid_base_search/grid_base_search - time_based_grid_search/time_based_grid_search model_predictive_trajectory_generator/model_predictive_trajectory_generator state_lattice_planner/state_lattice_planner prm_planner/prm_planner @@ -21,7 +18,6 @@ Path planning is the ability of a robot to search feasible and efficient path to rrt/rrt cubic_spline/cubic_spline bspline_path/bspline_path - catmull_rom_spline/catmull_rom_spline clothoid_path/clothoid_path eta3_spline/eta3_spline bezier_path/bezier_path @@ -32,4 +28,3 @@ Path planning is the ability of a robot to search feasible and efficient path to hybridastar/hybridastar frenet_frame_path/frenet_frame_path coverage_path/coverage_path - elastic_bands/elastic_bands \ No newline at end of file diff --git a/docs/modules/5_path_planning/prm_planner/prm_planner_main.rst b/_sources/modules/path_planning/prm_planner/prm_planner_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/prm_planner/prm_planner_main.rst rename to _sources/modules/path_planning/prm_planner/prm_planner_main.rst.txt diff --git a/docs/modules/5_path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst b/_sources/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst.txt similarity index 98% rename from docs/modules/5_path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst rename to _sources/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst.txt index 0412b3c9b3d..feec345bae8 100644 --- a/docs/modules/5_path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst +++ b/_sources/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst.txt @@ -101,6 +101,6 @@ References: ~~~~~~~~~~~ - `Local Path Planning And Motion Control For Agv In - Positioning <https://ieeexplore.ieee.org/document/637936/>`__ + Positioning <http://ieeexplore.ieee.org/document/637936/>`__ diff --git a/_sources/modules/path_planning/reeds_shepp_path/reeds_shepp_path_main.rst.txt b/_sources/modules/path_planning/reeds_shepp_path/reeds_shepp_path_main.rst.txt new file mode 100644 index 00000000000..81e565888ec --- /dev/null +++ b/_sources/modules/path_planning/reeds_shepp_path/reeds_shepp_path_main.rst.txt @@ -0,0 +1,17 @@ +Reeds Shepp planning +-------------------- + +A sample code with Reeds Shepp path planning. + +.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ReedsSheppPath/animation.gif?raw=true + +Ref: + +- `15.3.2 Reeds-Shepp + Curves <http://planning.cs.uiuc.edu/node822.html>`__ + +- `optimal paths for a car that goes both forwards and + backwards <https://pdfs.semanticscholar.org/932e/c495b1d0018fd59dee12a0bf74434fac7af4.pdf>`__ + +- `ghliu/pyReedsShepp: Implementation of Reeds Shepp + curve. <https://github.com/ghliu/pyReedsShepp>`__ diff --git a/docs/modules/5_path_planning/rrt/rrt_main.rst b/_sources/modules/path_planning/rrt/rrt_main.rst.txt similarity index 93% rename from docs/modules/5_path_planning/rrt/rrt_main.rst rename to _sources/modules/path_planning/rrt/rrt_main.rst.txt index e5f351a7baf..5a3a30dcff4 100644 --- a/docs/modules/5_path_planning/rrt/rrt_main.rst +++ b/_sources/modules/path_planning/rrt/rrt_main.rst.txt @@ -57,7 +57,7 @@ Ref: - `Informed RRT\*: Optimal Sampling-based Path Planning Focused via Direct Sampling of an Admissible Ellipsoidal - Heuristic <https://arxiv.org/pdf/1404.2334>`__ + Heuristic <https://arxiv.org/pdf/1404.2334.pdf>`__ .. _batch-informed-rrt*: @@ -90,10 +90,10 @@ PID is used for speed control. Ref: - `Motion Planning in Complex Environments using Closed-loop - Prediction <https://acl.mit.edu/papers/KuwataGNC08.pdf>`__ + Prediction <http://acl.mit.edu/papers/KuwataGNC08.pdf>`__ - `Real-time Motion Planning with Applications to Autonomous Urban - Driving <https://acl.mit.edu/papers/KuwataTCST09.pdf>`__ + Driving <http://acl.mit.edu/papers/KuwataTCST09.pdf>`__ - `[1601.06326] Sampling-based Algorithms for Optimal Motion Planning Using Closed-loop Prediction <https://arxiv.org/abs/1601.06326>`__ @@ -113,6 +113,6 @@ Ref: - `LQR-RRT\*: Optimal Sampling-Based Motion Planning with Automatically Derived Extension - Heuristics <https://lis.csail.mit.edu/pubs/perez-icra12.pdf>`__ + Heuristics <http://lis.csail.mit.edu/pubs/perez-icra12.pdf>`__ - `MahanFathi/LQR-RRTstar: LQR-RRT\* method is used for random motion planning of a simple pendulum in its phase plot <https://github.com/MahanFathi/LQR-RRTstar>`__ \ No newline at end of file diff --git a/docs/modules/5_path_planning/state_lattice_planner/state_lattice_planner_main.rst b/_sources/modules/path_planning/state_lattice_planner/state_lattice_planner_main.rst.txt similarity index 84% rename from docs/modules/5_path_planning/state_lattice_planner/state_lattice_planner_main.rst rename to _sources/modules/path_planning/state_lattice_planner/state_lattice_planner_main.rst.txt index d5e7ed17d14..3ef0c7eca21 100644 --- a/docs/modules/5_path_planning/state_lattice_planner/state_lattice_planner_main.rst +++ b/_sources/modules/path_planning/state_lattice_planner/state_lattice_planner_main.rst.txt @@ -25,9 +25,9 @@ Lane sampling Ref: - `Optimal rough terrain trajectory generation for wheeled mobile - robots <https://journals.sagepub.com/doi/pdf/10.1177/0278364906075328>`__ + robots <http://journals.sagepub.com/doi/pdf/10.1177/0278364906075328>`__ - `State Space Sampling of Feasible Motions for High-Performance Mobile Robot Navigation in Complex - Environments <https://www.frc.ri.cmu.edu/~alonzo/pubs/papers/JFR_08_SS_Sampling.pdf>`__ + Environments <http://www.frc.ri.cmu.edu/~alonzo/pubs/papers/JFR_08_SS_Sampling.pdf>`__ diff --git a/docs/modules/5_path_planning/visibility_road_map_planner/visibility_road_map_planner_main.rst b/_sources/modules/path_planning/visibility_road_map_planner/visibility_road_map_planner_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/visibility_road_map_planner/visibility_road_map_planner_main.rst rename to _sources/modules/path_planning/visibility_road_map_planner/visibility_road_map_planner_main.rst.txt diff --git a/docs/modules/5_path_planning/vrm_planner/vrm_planner_main.rst b/_sources/modules/path_planning/vrm_planner/vrm_planner_main.rst.txt similarity index 100% rename from docs/modules/5_path_planning/vrm_planner/vrm_planner_main.rst rename to _sources/modules/path_planning/vrm_planner/vrm_planner_main.rst.txt diff --git a/docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst b/_sources/modules/path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst.txt similarity index 96% rename from docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst rename to _sources/modules/path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst.txt index 23f1218a947..a1980ba17ea 100644 --- a/docs/modules/6_path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst +++ b/_sources/modules/path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst.txt @@ -60,7 +60,7 @@ Ref - `Shunichi09/nonlinear_control: Implementing the nonlinear model predictive control, sliding mode - control <https://github.com/Shunichi09/PythonLinearNonlinearControl>`__ + control <https://github.com/Shunichi09/nonlinear_control>`__ - `非線形モデル予測制御におけるCGMRES法をpythonで実装する - Qiita <https://qiita.com/MENDY/items/4108190a579395053924>`__ diff --git a/_sources/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst.txt b/_sources/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst.txt new file mode 100644 index 00000000000..68ea9c88b2a --- /dev/null +++ b/_sources/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst.txt @@ -0,0 +1,13 @@ +.. _linearquadratic-regulator-(lqr)-speed-and-steering-control: + +Linear–quadratic regulator (LQR) speed and steering control +----------------------------------------------------------- + +Path tracking simulation with LQR speed and steering control. + +.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_speed_steer_control/animation.gif + +References: +~~~~~~~~~~~ + +- `Towards fully autonomous driving: Systems and algorithms <http://ieeexplore.ieee.org/document/5940562/>`__ diff --git a/_sources/modules/path_tracking/lqr_steering_control/lqr_steering_control_main.rst.txt b/_sources/modules/path_tracking/lqr_steering_control/lqr_steering_control_main.rst.txt new file mode 100644 index 00000000000..bf6d6b5854c --- /dev/null +++ b/_sources/modules/path_tracking/lqr_steering_control/lqr_steering_control_main.rst.txt @@ -0,0 +1,14 @@ +.. _linearquadratic-regulator-(lqr)-steering-control: + +Linear–quadratic regulator (LQR) steering control +------------------------------------------------- + +Path tracking simulation with LQR steering control and PID speed +control. + +.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_steer_control/animation.gif + +References: +~~~~~~~~~~~ +- `ApolloAuto/apollo: An open autonomous driving platform <https://github.com/ApolloAuto/apollo>`_ + diff --git a/docs/modules/6_path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst b/_sources/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst.txt similarity index 98% rename from docs/modules/6_path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst rename to _sources/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst.txt index de55b545ba3..59a71666746 100644 --- a/docs/modules/6_path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst +++ b/_sources/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst.txt @@ -133,5 +133,5 @@ Reference - `Vehicle Dynamics and Control \| Rajesh Rajamani \| Springer <http://www.springer.com/us/book/9781461414322>`__ -- `MPC Book - MPC Lab @ - UC-Berkeley <https://sites.google.com/berkeley.edu/mpc-lab/mpc-course-material>`__ +- `MPC Course Material - MPC Lab @ + UC-Berkeley <http://www.mpc.berkeley.edu/mpc-course-material>`__ diff --git a/_sources/modules/path_tracking/path_tracking_main.rst.txt b/_sources/modules/path_tracking/path_tracking_main.rst.txt new file mode 100644 index 00000000000..504ba087952 --- /dev/null +++ b/_sources/modules/path_tracking/path_tracking_main.rst.txt @@ -0,0 +1,16 @@ +.. _path_tracking: + +Path Tracking +============= + +.. toctree:: + :maxdepth: 2 + :caption: Contents + + pure_pursuit_tracking/pure_pursuit_tracking + stanley_control/stanley_control + rear_wheel_feedback_control/rear_wheel_feedback_control + lqr_steering_control/lqr_steering_control + lqr_speed_and_steering_control/lqr_speed_and_steering_control + model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control + cgmres_nmpc/cgmres_nmpc diff --git a/docs/modules/6_path_tracking/pure_pursuit_tracking/pure_pursuit_tracking_main.rst b/_sources/modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking_main.rst.txt similarity index 100% rename from docs/modules/6_path_tracking/pure_pursuit_tracking/pure_pursuit_tracking_main.rst rename to _sources/modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking_main.rst.txt diff --git a/docs/modules/6_path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control_main.rst b/_sources/modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control_main.rst.txt similarity index 100% rename from docs/modules/6_path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control_main.rst rename to _sources/modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control_main.rst.txt diff --git a/docs/modules/6_path_tracking/stanley_control/stanley_control_main.rst b/_sources/modules/path_tracking/stanley_control/stanley_control_main.rst.txt similarity index 100% rename from docs/modules/6_path_tracking/stanley_control/stanley_control_main.rst rename to _sources/modules/path_tracking/stanley_control/stanley_control_main.rst.txt diff --git a/docs/modules/4_slam/FastSLAM1/FastSLAM1_main.rst b/_sources/modules/slam/FastSLAM1/FastSLAM1_main.rst.txt similarity index 100% rename from docs/modules/4_slam/FastSLAM1/FastSLAM1_main.rst rename to _sources/modules/slam/FastSLAM1/FastSLAM1_main.rst.txt diff --git a/docs/modules/4_slam/FastSLAM2/FastSLAM2_main.rst b/_sources/modules/slam/FastSLAM2/FastSLAM2_main.rst.txt similarity index 100% rename from docs/modules/4_slam/FastSLAM2/FastSLAM2_main.rst rename to _sources/modules/slam/FastSLAM2/FastSLAM2_main.rst.txt diff --git a/docs/modules/4_slam/ekf_slam/ekf_slam_main.rst b/_sources/modules/slam/ekf_slam/ekf_slam_main.rst.txt similarity index 95% rename from docs/modules/4_slam/ekf_slam/ekf_slam_main.rst rename to _sources/modules/slam/ekf_slam/ekf_slam_main.rst.txt index b27971225ec..70a7d131aee 100644 --- a/docs/modules/4_slam/ekf_slam/ekf_slam_main.rst +++ b/_sources/modules/slam/ekf_slam/ekf_slam_main.rst.txt @@ -63,27 +63,27 @@ Take care to note the difference between :math:`X` (state) and :math:`x` original author: Atsushi Sakai (@Atsushi_twi) notebook author: Andrew Tu (drewtu2) """ - + import math import numpy as np %matplotlib notebook import matplotlib.pyplot as plt - - + + # EKF state covariance Cx = np.diag([0.5, 0.5, np.deg2rad(30.0)])**2 # Change in covariance - + # Simulation parameter Qsim = np.diag([0.2, np.deg2rad(1.0)])**2 # Sensor Noise Rsim = np.diag([1.0, np.deg2rad(10.0)])**2 # Process Noise - + DT = 0.1 # time tick [s] SIM_TIME = 50.0 # simulation time [s] MAX_RANGE = 20.0 # maximum observation range M_DIST_TH = 2.0 # Threshold of Mahalanobis distance for data association. STATE_SIZE = 3 # State size [x,y,yaw] LM_SIZE = 2 # LM state size [x,y] - + show_animation = True Algorithm Walk through @@ -97,22 +97,23 @@ the estimated state and measurements def ekf_slam(xEst, PEst, u, z): """ - Performs an iteration of EKF SLAM from the available information. - + Performs an iteration of EKF SLAM from the available information. + :param xEst: the belief in last position :param PEst: the uncertainty in last position - :param u: the control function applied to the last position + :param u: the control function applied to the last position :param z: measurements at this step :returns: the next estimated position and associated covariance """ - + S = STATE_SIZE + # Predict - xEst, PEst = predict(xEst, PEst, u) + xEst, PEst, G, Fx = predict(xEst, PEst, u) initP = np.eye(2) - + # Update - xEst, PEst = update(xEst, PEst, z, initP) - + xEst, PEst = update(xEst, PEst, u, z, initP) + return xEst, PEst @@ -169,25 +170,26 @@ the landmarks. def predict(xEst, PEst, u): """ Performs the prediction step of EKF SLAM - + :param xEst: nx1 state vector :param PEst: nxn covariance matrix :param u: 2x1 control vector :returns: predicted state vector, predicted covariance, jacobian of control vector, transition fx """ - G, Fx = jacob_motion(xEst, u) - xEst[0:STATE_SIZE] = motion_model(xEst[0:STATE_SIZE], u) + S = STATE_SIZE + G, Fx = jacob_motion(xEst[0:S], u) + xEst[0:S] = motion_model(xEst[0:S], u) # Fx is an an identity matrix of size (STATE_SIZE) # sigma = G*sigma*G.T + Noise - PEst = G.T @ PEst @ G + Fx.T @ Cx @ Fx - return xEst, PEst + PEst[0:S, 0:S] = G.T @ PEst[0:S, 0:S] @ G + Fx.T @ Cx @ Fx + return xEst, PEst, G, Fx .. code:: ipython3 def motion_model(x, u): """ Computes the motion model based on current state and input function. - + :param x: 3x1 pose estimation :param u: 2x1 control input [v; w] :returns: the resulting state after the control function is applied @@ -195,11 +197,11 @@ the landmarks. F = np.array([[1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0]]) - + B = np.array([[DT * math.cos(x[2, 0]), 0], [DT * math.sin(x[2, 0]), 0], [0.0, DT]]) - + x = (F @ x) + (B @ u) return x @@ -259,21 +261,22 @@ the changing uncertainty. .. code:: ipython3 - def update(xEst, PEst, z, initP): + def update(xEst, PEst, u, z, initP): """ Performs the update step of EKF SLAM - + :param xEst: nx1 the predicted pose of the system and the pose of the landmarks :param PEst: nxn the predicted covariance + :param u: 2x1 the control function :param z: the measurements read at new position :param initP: 2x2 an identity matrix acting as the initial covariance :returns: the updated state and covariance for the system """ for iz in range(len(z[:, 0])): # for each observation minid = search_correspond_LM_ID(xEst, PEst, z[iz, 0:2]) # associate to a known landmark - + nLM = calc_n_LM(xEst) # number of landmarks we currently know about - + if minid == nLM: # Landmark is a NEW landmark print("New LM") # Extend state and covariance matrix @@ -282,14 +285,14 @@ the changing uncertainty. np.hstack((np.zeros((LM_SIZE, len(xEst))), initP)))) xEst = xAug PEst = PAug - + lm = get_LM_Pos_from_state(xEst, minid) y, S, H = calc_innovation(lm, xEst, PEst, z[iz, 0:2], minid) - + K = (PEst @ H.T) @ np.linalg.inv(S) # Calculate Kalman Gain xEst = xEst + (K @ y) PEst = (np.eye(len(xEst)) - (K @ H)) @ PEst - + xEst[2] = pi_2_pi(xEst[2]) return xEst, PEst @@ -299,7 +302,7 @@ the changing uncertainty. def calc_innovation(lm, xEst, PEst, z, LMid): """ Calculates the innovation based on expected position and landmark position - + :param lm: landmark position :param xEst: estimated position/state :param PEst: estimated covariance @@ -312,19 +315,19 @@ the changing uncertainty. zangle = math.atan2(delta[1, 0], delta[0, 0]) - xEst[2, 0] zp = np.array([[math.sqrt(q), pi_2_pi(zangle)]]) # zp is the expected measurement based on xEst and the expected landmark position - + y = (z - zp).T # y = innovation y[1] = pi_2_pi(y[1]) - + H = jacobH(q, delta, xEst, LMid + 1) S = H @ PEst @ H.T + Cx[0:2, 0:2] - + return y, S, H - + def jacobH(q, delta, x, i): """ Calculates the jacobian of the measurement function - + :param q: the range from the system pose to the landmark :param delta: the difference between a landmark position and the estimated system position :param x: the state, including the estimated system position @@ -334,17 +337,17 @@ the changing uncertainty. sq = math.sqrt(q) G = np.array([[-sq * delta[0, 0], - sq * delta[1, 0], 0, sq * delta[0, 0], sq * delta[1, 0]], [delta[1, 0], - delta[0, 0], - q, - delta[1, 0], delta[0, 0]]]) - + G = G / q nLM = calc_n_LM(x) F1 = np.hstack((np.eye(3), np.zeros((3, 2 * nLM)))) F2 = np.hstack((np.zeros((2, 3)), np.zeros((2, 2 * (i - 1))), np.eye(2), np.zeros((2, 2 * nLM - 2 * i)))) - + F = np.vstack((F1, F2)) - + H = G @ F - + return H Observation Step @@ -367,17 +370,17 @@ reckoning and control functions are passed along here as well. :param xd: the current noisy estimate of the system :param u: the current control input :param RFID: the true position of the landmarks - - :returns: Computes the true position, observations, dead reckoning (noisy) position, + + :returns: Computes the true position, observations, dead reckoning (noisy) position, and noisy control function """ xTrue = motion_model(xTrue, u) - + # add noise to gps x-y z = np.zeros((0, 3)) - + for i in range(len(RFID[:, 0])): # Test all beacons, only add the ones we can see (within MAX_RANGE) - + dx = RFID[i, 0] - xTrue[0, 0] dy = RFID[i, 1] - xTrue[1, 0] d = math.sqrt(dx**2 + dy**2) @@ -387,12 +390,12 @@ reckoning and control functions are passed along here as well. anglen = angle + np.random.randn() * Qsim[1, 1] # add noise zi = np.array([dn, anglen, i]) z = np.vstack((z, zi)) - + # add noise to input ud = np.array([[ u[0, 0] + np.random.randn() * Rsim[0, 0], u[1, 0] + np.random.randn() * Rsim[1, 1]]]).T - + xd = motion_model(xd, ud) return xTrue, z, xd, ud @@ -406,30 +409,32 @@ reckoning and control functions are passed along here as well. """ n = int((len(x) - STATE_SIZE) / LM_SIZE) return n - - + + def jacob_motion(x, u): """ - Calculates the jacobian of motion model. - + Calculates the jacobian of motion model. + :param x: The state, including the estimated position of the system :param u: The control function :returns: G: Jacobian Fx: STATE_SIZE x (STATE_SIZE + 2 * num_landmarks) matrix where the left side is an identity matrix """ - + # [eye(3) [0 x y; 0 x y; 0 x y]] Fx = np.hstack((np.eye(STATE_SIZE), np.zeros( (STATE_SIZE, LM_SIZE * calc_n_LM(x))))) - + jF = np.array([[0.0, 0.0, -DT * u[0] * math.sin(x[2, 0])], [0.0, 0.0, DT * u[0] * math.cos(x[2, 0])], [0.0, 0.0, 0.0]],dtype=object) - + G = np.eye(STATE_SIZE) + Fx.T @ jF @ Fx if calc_n_LM(x) > 0: print(Fx.shape) return G, Fx, + + .. code:: ipython3 @@ -437,68 +442,68 @@ reckoning and control functions are passed along here as well. def calc_LM_Pos(x, z): """ Calculates the pose in the world coordinate frame of a landmark at the given measurement. - + :param x: [x; y; theta] :param z: [range; bearing] :returns: [x; y] for given measurement """ zp = np.zeros((2, 1)) - + zp[0, 0] = x[0, 0] + z[0] * math.cos(x[2, 0] + z[1]) zp[1, 0] = x[1, 0] + z[0] * math.sin(x[2, 0] + z[1]) #zp[0, 0] = x[0, 0] + z[0, 0] * math.cos(x[2, 0] + z[0, 1]) #zp[1, 0] = x[1, 0] + z[0, 0] * math.sin(x[2, 0] + z[0, 1]) - + return zp - - + + def get_LM_Pos_from_state(x, ind): """ Returns the position of a given landmark - + :param x: The state containing all landmark positions :param ind: landmark id :returns: The position of the landmark """ lm = x[STATE_SIZE + LM_SIZE * ind: STATE_SIZE + LM_SIZE * (ind + 1), :] - + return lm - - + + def search_correspond_LM_ID(xAug, PAug, zi): """ Landmark association with Mahalanobis distance. - - If this landmark is at least M_DIST_TH units away from all known landmarks, + + If this landmark is at least M_DIST_TH units away from all known landmarks, it is a NEW landmark. - + :param xAug: The estimated state :param PAug: The estimated covariance :param zi: the read measurements of specific landmark :returns: landmark id """ - + nLM = calc_n_LM(xAug) - + mdist = [] - + for i in range(nLM): lm = get_LM_Pos_from_state(xAug, i) y, S, H = calc_innovation(lm, xAug, PAug, zi, i) mdist.append(y.T @ np.linalg.inv(S) @ y) - + mdist.append(M_DIST_TH) # new landmark - + minid = mdist.index(min(mdist)) - + return minid - + def calc_input(): v = 1.0 # [m/s] yawrate = 0.1 # [rad/s] u = np.array([[v, yawrate]]).T return u - + def pi_2_pi(angle): return (angle + math.pi) % (2 * math.pi) - math.pi @@ -506,53 +511,53 @@ reckoning and control functions are passed along here as well. def main(): print(" start!!") - + time = 0.0 - + # RFID positions [x, y] RFID = np.array([[10.0, -2.0], [15.0, 10.0], [3.0, 15.0], [-5.0, 20.0]]) - + # State Vector [x y yaw v]' xEst = np.zeros((STATE_SIZE, 1)) xTrue = np.zeros((STATE_SIZE, 1)) PEst = np.eye(STATE_SIZE) - + xDR = np.zeros((STATE_SIZE, 1)) # Dead reckoning - + # history hxEst = xEst hxTrue = xTrue hxDR = xTrue - + while SIM_TIME >= time: time += DT u = calc_input() - + xTrue, z, xDR, ud = observation(xTrue, xDR, u, RFID) - + xEst, PEst = ekf_slam(xEst, PEst, ud, z) - + x_state = xEst[0:STATE_SIZE] - + # store data history hxEst = np.hstack((hxEst, x_state)) hxDR = np.hstack((hxDR, xDR)) hxTrue = np.hstack((hxTrue, xTrue)) - + if show_animation: # pragma: no cover plt.cla() - + plt.plot(RFID[:, 0], RFID[:, 1], "*k") plt.plot(xEst[0], xEst[1], ".r") - + # plot landmark for i in range(calc_n_LM(xEst)): plt.plot(xEst[STATE_SIZE + i * 2], xEst[STATE_SIZE + i * 2 + 1], "xg") - + plt.plot(hxTrue[0, :], hxTrue[1, :], "-b") plt.plot(hxDR[0, :], @@ -582,3 +587,5 @@ References: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - `PROBABILISTIC ROBOTICS <http://www.probabilistic-robotics.org/>`_ + + diff --git a/docs/modules/4_slam/graph_slam/graph_slam_main.rst b/_sources/modules/slam/graph_slam/graph_slam_main.rst.txt similarity index 100% rename from docs/modules/4_slam/graph_slam/graph_slam_main.rst rename to _sources/modules/slam/graph_slam/graph_slam_main.rst.txt diff --git a/docs/modules/4_slam/iterative_closest_point_matching/iterative_closest_point_matching_main.rst b/_sources/modules/slam/iterative_closest_point_matching/iterative_closest_point_matching_main.rst.txt similarity index 100% rename from docs/modules/4_slam/iterative_closest_point_matching/iterative_closest_point_matching_main.rst rename to _sources/modules/slam/iterative_closest_point_matching/iterative_closest_point_matching_main.rst.txt diff --git a/_sources/modules/slam/slam_main.rst.txt b/_sources/modules/slam/slam_main.rst.txt new file mode 100644 index 00000000000..86befa6e357 --- /dev/null +++ b/_sources/modules/slam/slam_main.rst.txt @@ -0,0 +1,16 @@ +.. _slam: + +SLAM +==== + +Simultaneous Localization and Mapping(SLAM) examples + +.. toctree:: + :maxdepth: 2 + :caption: Contents + + iterative_closest_point_matching/iterative_closest_point_matching + ekf_slam/ekf_slam + FastSLAM1/FastSLAM1 + FastSLAM2/FastSLAM2 + graph_slam/graph_slam diff --git a/docs/modules/11_utils/plot/plot_main.rst b/_sources/modules/utils/plot/plot_main.rst.txt similarity index 100% rename from docs/modules/11_utils/plot/plot_main.rst rename to _sources/modules/utils/plot/plot_main.rst.txt diff --git a/docs/modules/11_utils/utils_main.rst b/_sources/modules/utils/utils_main.rst.txt similarity index 90% rename from docs/modules/11_utils/utils_main.rst rename to _sources/modules/utils/utils_main.rst.txt index 95c982b077f..ff79a262053 100644 --- a/docs/modules/11_utils/utils_main.rst +++ b/_sources/modules/utils/utils_main.rst.txt @@ -1,4 +1,4 @@ -.. _`utils`: +.. _utils: Utilities ========== diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000000..603f6a8798e --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,905 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 00000000000..92fad4b5c0b --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="44" height="44" viewBox="0 0 24 24" stroke-width="2" stroke="#22863a" fill="none" stroke-linecap="round" stroke-linejoin="round"> + <path stroke="none" d="M0 0h24v24H0z" fill="none"/> + <path d="M5 12l5 5l10 -10" /> +</svg> diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 00000000000..54b3c463811 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body},i="";return"string"==typeof t?(e=t,n="rtl"===document.documentElement.getAttribute("dir"),(o=document.createElement("textarea")).style.fontSize="12pt",o.style.border="0",o.style.padding="0",o.style.margin="0",o.style.position="absolute",o.style[n?"right":"left"]="-9999px",n=window.pageYOffset||document.documentElement.scrollTop,o.style.top="".concat(n,"px"),o.setAttribute("readonly",""),o.value=e,o=o,r.container.appendChild(o),i=c()(o),a("copy"),o.remove()):(i=c()(t),a("copy")),i};function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var s=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},e=t.action,n=void 0===e?"copy":e,o=t.container,e=t.target,t=t.text;if("copy"!==n&&"cut"!==n)throw new Error('Invalid "action" value, use either "copy" or "cut"');if(void 0!==e){if(!e||"object"!==r(e)||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===n&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===n&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes')}return t?l(t,{container:o}):e?"cut"===n?f(e):l(e,{container:o}):void 0};function d(t){return(d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function p(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function y(t,e){return(y=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(n){var o=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=m(n);return t=o?(t=m(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==d(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function m(t){return(m=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function v(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}var o=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&y(t,e)}(r,i());var t,e,n,o=h(r);function r(t,e){var n;return function(t){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}(this),(n=o.call(this)).resolveOptions(e),n.listenClick(t),n}return t=r,n=[{key:"copy",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body};return l(t,e)}},{key:"cut",value:function(t){return f(t)}},{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===d(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=u()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget,t=s({action:this.action(e),container:this.container,target:this.target(e),text:this.text(e)});this.emit(t?"success":"error",{action:this.action,text:t,trigger:e,clearSelection:function(){e&&e.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(t){return v("action",t)}},{key:"defaultTarget",value:function(t){t=v("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return v("text",t)}},{key:"destroy",value:function(){this.listener.destroy()}}])&&p(t.prototype,e),n&&p(t,n),r}()},828:function(t){var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:function(t,e,n){var u=n(828);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=u(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},879:function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:function(t,e,n){var f=n(879),l=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!f.string(e))throw new TypeError("Second argument must be a String");if(!f.fn(n))throw new TypeError("Third argument must be a Function");if(f.node(t))return c=e,a=n,(u=t).addEventListener(c,a),{destroy:function(){u.removeEventListener(c,a)}};if(f.nodeList(t))return o=t,r=e,i=n,Array.prototype.forEach.call(o,function(t){t.addEventListener(r,i)}),{destroy:function(){Array.prototype.forEach.call(o,function(t){t.removeEventListener(r,i)})}};if(f.string(t))return t=t,e=e,n=n,l(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,u,c,a}},817:function(t){t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:function(t){function e(){}e.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,u=o.length;i<u;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},r={},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,{a:e}),e},o.d=function(t,e){for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o(686).default;function o(t){if(r[t])return r[t].exports;var e=r[t]={exports:{}};return n[t](e,e.exports,o),e.exports}var n,r}); \ No newline at end of file diff --git a/_static/copy-button.svg b/_static/copy-button.svg new file mode 100644 index 00000000000..9c074dae528 --- /dev/null +++ b/_static/copy-button.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round"> + <path stroke="none" d="M0 0h24v24H0z" fill="none"/> + <rect x="8" y="8" width="12" height="12" rx="2" /> + <path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" /> +</svg> diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 00000000000..f1916ec7d1b --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + * <p class="o-tooltip--left" data-tooltip="Hey">Short</p> + */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 00000000000..2ea7ff3e217 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-check" width="44" height="44" viewBox="0 0 24 24" stroke-width="2" stroke="#22863a" fill="none" stroke-linecap="round" stroke-linejoin="round"> + <title>${messages[locale]['copy_success']}</title> + <path stroke="none" d="M0 0h24v24H0z" fill="none"/> + <path d="M5 12l5 5l10 -10" /> +</svg>` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round"> + <title>${messages[locale]['copy_to_clipboard']}</title> + <path stroke="none" d="M0 0h24v24H0z" fill="none"/> + <rect x="8" y="8" width="12" height="12" rx="2" /> + <path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" /> +</svg>` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `<button class="copybtn o-tooltip--left" data-tooltip="${messages[locale]['copy']}" data-clipboard-target="#${id}"> + ${iconCopy} + </button>` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 00000000000..dbe1aaad79c --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000000..e380325bc6e --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000000..6cb60000181 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000000..7059e23142a Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000000..f815f63f99d Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000000..f2c76e5bda1 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000000..e9f60ca953f Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000000..855c845e538 --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg> +<metadata> +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. +</metadata> +<defs> +<font id="FontAwesome" horiz-adv-x="1536" > + <font-face + font-family="FontAwesome" + font-weight="400" + font-stretch="normal" + units-per-em="1792" + panose-1="0 0 0 0 0 0 0 0 0 0" + ascent="1536" + descent="-256" + bbox="-1.02083 -256.962 2304.6 1537.02" + underline-thickness="0" + underline-position="0" + unicode-range="U+0020-F500" + /> +<missing-glyph horiz-adv-x="896" +d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" /> + <glyph glyph-name=".notdef" horiz-adv-x="896" +d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" /> + <glyph glyph-name=".null" horiz-adv-x="0" + /> + <glyph glyph-name="nonmarkingreturn" horiz-adv-x="597" + /> + <glyph glyph-name="space" unicode=" " horiz-adv-x="448" + /> + <glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1792" + /> + <glyph glyph-name="copyright" unicode="©" horiz-adv-x="1792" + /> + <glyph glyph-name="registered" unicode="®" horiz-adv-x="1792" + /> + <glyph glyph-name="acute" unicode="´" horiz-adv-x="1792" + /> + <glyph glyph-name="AE" unicode="Æ" horiz-adv-x="1792" + /> + <glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1792" + /> + <glyph glyph-name="trademark" unicode="™" horiz-adv-x="1792" + /> + <glyph glyph-name="infinity" unicode="∞" horiz-adv-x="1792" + /> + <glyph glyph-name="notequal" unicode="≠" horiz-adv-x="1792" + /> + <glyph glyph-name="glass" unicode="" horiz-adv-x="1792" +d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" /> + <glyph glyph-name="music" unicode="" +d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 +t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" /> + <glyph glyph-name="search" unicode="" horiz-adv-x="1664" +d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 +t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> + <glyph glyph-name="envelope" unicode="" horiz-adv-x="1792" +d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 +t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z +M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="heart" unicode="" horiz-adv-x="1792" +d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 +q-18 -18 -44 -18z" /> + <glyph glyph-name="star" unicode="" horiz-adv-x="1664" +d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 +l502 -73q56 -9 56 -46z" /> + <glyph glyph-name="star_empty" unicode="" horiz-adv-x="1664" +d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 +l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" /> + <glyph glyph-name="user" unicode="" horiz-adv-x="1280" +d="M1280 137q0 -109 -62.5 -187t-150.5 -78h-854q-88 0 -150.5 78t-62.5 187q0 85 8.5 160.5t31.5 152t58.5 131t94 89t134.5 34.5q131 -128 313 -128t313 128q76 0 134.5 -34.5t94 -89t58.5 -131t31.5 -152t8.5 -160.5zM1024 1024q0 -159 -112.5 -271.5t-271.5 -112.5 +t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="film" unicode="" horiz-adv-x="1920" +d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 +q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 +t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 +q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 +t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="th_large" unicode="" horiz-adv-x="1664" +d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 +h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> + <glyph glyph-name="th" unicode="" horiz-adv-x="1792" +d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 +h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 +q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" /> + <glyph glyph-name="th_list" unicode="" horiz-adv-x="1792" +d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 +h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" /> + <glyph glyph-name="ok" unicode="" horiz-adv-x="1792" +d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" /> + <glyph glyph-name="remove" unicode="" horiz-adv-x="1408" +d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 +t-28 -68l-294 -294l294 -294q28 -28 28 -68z" /> + <glyph glyph-name="zoom_in" unicode="" horiz-adv-x="1664" +d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 +q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 +t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" /> + <glyph glyph-name="zoom_out" unicode="" horiz-adv-x="1664" +d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z +M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z +" /> + <glyph glyph-name="off" unicode="" +d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 +t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" /> + <glyph glyph-name="signal" unicode="" horiz-adv-x="1792" +d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 +v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" /> + <glyph glyph-name="cog" unicode="" +d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 +q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 +l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 +q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" /> + <glyph glyph-name="trash" unicode="" horiz-adv-x="1408" +d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 +q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 +q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> + <glyph glyph-name="home" unicode="" horiz-adv-x="1664" +d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 +l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" /> + <glyph glyph-name="file_alt" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +" /> + <glyph glyph-name="time" unicode="" +d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="road" unicode="" horiz-adv-x="1920" +d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 +q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" /> + <glyph glyph-name="download_alt" unicode="" horiz-adv-x="1664" +d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 +q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" /> + <glyph glyph-name="download" unicode="" +d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 +t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="upload" unicode="" +d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 +t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="inbox" unicode="" +d="M1023 576h316q-1 3 -2.5 8.5t-2.5 7.5l-212 496h-708l-212 -496q-1 -3 -2.5 -8.5t-2.5 -7.5h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 +q25 -61 25 -123z" /> + <glyph glyph-name="play_circle" unicode="" +d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="repeat" unicode="" +d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q15 0 25 -9 +l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" /> + <glyph glyph-name="refresh" unicode="" +d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 +q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 +q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" /> + <glyph glyph-name="list_alt" unicode="" horiz-adv-x="1792" +d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z +M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 +t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 +t47 -113z" /> + <glyph glyph-name="lock" unicode="" horiz-adv-x="1152" +d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" /> + <glyph glyph-name="flag" unicode="" horiz-adv-x="1792" +d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 +t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" /> + <glyph glyph-name="headphones" unicode="" horiz-adv-x="1664" +d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 +t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 +t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" /> + <glyph glyph-name="volume_off" unicode="" horiz-adv-x="768" +d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" /> + <glyph glyph-name="volume_down" unicode="" horiz-adv-x="1152" +d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36 +t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" /> + <glyph glyph-name="volume_up" unicode="" horiz-adv-x="1664" +d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36 +t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 +t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 +t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" /> + <glyph glyph-name="qrcode" unicode="" horiz-adv-x="1408" +d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z +M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" /> + <glyph glyph-name="barcode" unicode="" horiz-adv-x="1792" +d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z +M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" /> + <glyph glyph-name="tag" unicode="" +d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 +l715 -714q37 -39 37 -91z" /> + <glyph glyph-name="tags" unicode="" horiz-adv-x="1920" +d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 +l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" /> + <glyph glyph-name="book" unicode="" horiz-adv-x="1664" +d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 +q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 +q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 +t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" /> + <glyph glyph-name="bookmark" unicode="" horiz-adv-x="1280" +d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> + <glyph glyph-name="print" unicode="" horiz-adv-x="1664" +d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 +v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" /> + <glyph glyph-name="camera" unicode="" horiz-adv-x="1920" +d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 +q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="font" unicode="" horiz-adv-x="1664" +d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 +q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -5 -0.5 -13.5t-0.5 -12.5q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 +q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" /> + <glyph glyph-name="bold" unicode="" horiz-adv-x="1408" +d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 +q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 +t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68 -0.5t68 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 +t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" /> + <glyph glyph-name="italic" unicode="" horiz-adv-x="1024" +d="M0 -126l17 85q22 7 61.5 16.5t72 19t59.5 23.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 +q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" /> + <glyph glyph-name="text_height" unicode="" horiz-adv-x="1792" +d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 +t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 +q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 +q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" /> + <glyph glyph-name="text_width" unicode="" +d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 +t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 +q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 +t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 +t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" /> + <glyph glyph-name="align_left" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 +t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="align_center" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 +h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" /> + <glyph glyph-name="align_right" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 +t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="align_justify" unicode="" horiz-adv-x="1792" +d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 +t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> + <glyph glyph-name="list" unicode="" horiz-adv-x="1792" +d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 +t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 +q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 +t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 +q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="indent_left" unicode="" horiz-adv-x="1792" +d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 +t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 +q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="indent_right" unicode="" horiz-adv-x="1792" +d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 +t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 +q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="facetime_video" unicode="" horiz-adv-x="1792" +d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 +q39 -17 39 -59z" /> + <glyph glyph-name="picture" unicode="" horiz-adv-x="1920" +d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 +q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="pencil" unicode="" +d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 +q53 0 91 -38l235 -234q37 -39 37 -91z" /> + <glyph glyph-name="map_marker" unicode="" horiz-adv-x="1024" +d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" /> + <glyph glyph-name="adjust" unicode="" +d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="tint" unicode="" horiz-adv-x="1024" +d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 +q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" /> + <glyph glyph-name="edit" unicode="" horiz-adv-x="1792" +d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 +q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 +l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" /> + <glyph glyph-name="share" unicode="" horiz-adv-x="1664" +d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 +q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 +t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" /> + <glyph glyph-name="check" unicode="" horiz-adv-x="1664" +d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 +q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 +q24 -24 24 -57t-24 -57z" /> + <glyph glyph-name="move" unicode="" horiz-adv-x="1792" +d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 +t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> + <glyph glyph-name="step_backward" unicode="" horiz-adv-x="1024" +d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19z" /> + <glyph glyph-name="fast_backward" unicode="" horiz-adv-x="1792" +d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19l710 710 +q19 19 32 13t13 -32v-710q4 10 13 19z" /> + <glyph glyph-name="backward" unicode="" horiz-adv-x="1664" +d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q4 10 13 19z" /> + <glyph glyph-name="play" unicode="" horiz-adv-x="1408" +d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" /> + <glyph glyph-name="pause" unicode="" +d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" /> + <glyph glyph-name="stop" unicode="" +d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> + <glyph glyph-name="forward" unicode="" horiz-adv-x="1664" +d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" /> + <glyph glyph-name="fast_forward" unicode="" horiz-adv-x="1792" +d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19l-710 -710 +q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" /> + <glyph glyph-name="step_forward" unicode="" horiz-adv-x="1024" +d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19z" /> + <glyph glyph-name="eject" unicode="" horiz-adv-x="1538" +d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" /> + <glyph glyph-name="chevron_left" unicode="" horiz-adv-x="1280" +d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" /> + <glyph glyph-name="chevron_right" unicode="" horiz-adv-x="1280" +d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" /> + <glyph glyph-name="plus_sign" unicode="" +d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 +t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="minus_sign" unicode="" +d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 +t103 -385.5z" /> + <glyph glyph-name="remove_sign" unicode="" +d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 +q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ok_sign" unicode="" +d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="question_sign" unicode="" +d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 +q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="info_sign" unicode="" +d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 +t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="screenshot" unicode="" +d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 +q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 +q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" /> + <glyph glyph-name="remove_circle" unicode="" +d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 +l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 +t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ok_circle" unicode="" +d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 +t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ban_circle" unicode="" +d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 +t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" /> + <glyph glyph-name="arrow_left" unicode="" +d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 +t32.5 -90.5z" /> + <glyph glyph-name="arrow_right" unicode="" +d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" /> + <glyph glyph-name="arrow_up" unicode="" horiz-adv-x="1664" +d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 +q37 -39 37 -91z" /> + <glyph glyph-name="arrow_down" unicode="" horiz-adv-x="1664" +d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" /> + <glyph glyph-name="share_alt" unicode="" horiz-adv-x="1792" +d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 +t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" /> + <glyph glyph-name="resize_full" unicode="" +d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 +q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" /> + <glyph glyph-name="resize_small" unicode="" +d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 +t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" /> + <glyph glyph-name="plus" unicode="" horiz-adv-x="1408" +d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" /> + <glyph glyph-name="minus" unicode="" horiz-adv-x="1408" +d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" /> + <glyph glyph-name="asterisk" unicode="" horiz-adv-x="1664" +d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 +q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" /> + <glyph glyph-name="exclamation_sign" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 +q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" /> + <glyph glyph-name="gift" unicode="" +d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 +q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 +t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" /> + <glyph glyph-name="leaf" unicode="" horiz-adv-x="1792" +d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 +q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-43 0 -63.5 17.5t-45.5 59.5q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 +t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" /> + <glyph glyph-name="fire" unicode="" horiz-adv-x="1408" +d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 +q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" /> + <glyph glyph-name="eye_open" unicode="" horiz-adv-x="1792" +d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 +t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" /> + <glyph glyph-name="eye_close" unicode="" horiz-adv-x="1792" +d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 +q-106 -189 -316 -567t-315 -566l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 +q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z +" /> + <glyph glyph-name="warning_sign" unicode="" horiz-adv-x="1792" +d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 +q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" /> + <glyph glyph-name="plane" unicode="" horiz-adv-x="1408" +d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 +q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" /> + <glyph glyph-name="calendar" unicode="" horiz-adv-x="1664" +d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z +M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 +q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 +h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="random" unicode="" horiz-adv-x="1792" +d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 +t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 +v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 +t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> + <glyph glyph-name="comment" unicode="" horiz-adv-x="1792" +d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 +q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" /> + <glyph glyph-name="magnet" unicode="" +d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 +q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" /> + <glyph glyph-name="chevron_up" unicode="" horiz-adv-x="1792" +d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" /> + <glyph glyph-name="chevron_down" unicode="" horiz-adv-x="1792" +d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" /> + <glyph glyph-name="retweet" unicode="" horiz-adv-x="1920" +d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -10 7 -21 +zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z +" /> + <glyph glyph-name="shopping_cart" unicode="" horiz-adv-x="1664" +d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 +t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" /> + <glyph glyph-name="folder_close" unicode="" horiz-adv-x="1664" +d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> + <glyph glyph-name="folder_open" unicode="" horiz-adv-x="1920" +d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 +t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" /> + <glyph glyph-name="resize_vertical" unicode="" horiz-adv-x="768" +d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" /> + <glyph glyph-name="resize_horizontal" unicode="" horiz-adv-x="1792" +d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" /> + <glyph glyph-name="bar_chart" unicode="" horiz-adv-x="2048" +d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" /> + <glyph glyph-name="twitter_sign" unicode="" +d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 +q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 +t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="facebook_sign" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 +q0 119 84.5 203.5t203.5 84.5h960z" /> + <glyph glyph-name="camera_retro" unicode="" horiz-adv-x="1792" +d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 +t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 +q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="key" unicode="" horiz-adv-x="1792" +d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 +l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 +t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" /> + <glyph glyph-name="cogs" unicode="" horiz-adv-x="1920" +d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 +t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -11 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 +l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 +l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -8 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 +q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 +t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 +q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 +q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" /> + <glyph glyph-name="comments" unicode="" horiz-adv-x="1792" +d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 +q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 +q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" /> + <glyph glyph-name="thumbs_up_alt" unicode="" +d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 +t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 +q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 +q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" /> + <glyph glyph-name="thumbs_down_alt" unicode="" +d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 31 18 69q0 37 -17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 +t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z +M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 +h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -73 49 -163z" /> + <glyph glyph-name="star_half" unicode="" horiz-adv-x="896" +d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" /> + <glyph glyph-name="heart_empty" unicode="" horiz-adv-x="1792" +d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 +q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 +q224 0 351 -124t127 -344z" /> + <glyph glyph-name="signout" unicode="" horiz-adv-x="1664" +d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 +q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" /> + <glyph glyph-name="linkedin_sign" unicode="" +d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 +q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="pushpin" unicode="" horiz-adv-x="1152" +d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 +t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" /> + <glyph glyph-name="external_link" unicode="" horiz-adv-x="1792" +d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 +q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" /> + <glyph glyph-name="signin" unicode="" +d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 +q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="trophy" unicode="" horiz-adv-x="1664" +d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 +t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 +q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" /> + <glyph glyph-name="github_sign" unicode="" +d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4 +q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4 +t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16 +q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="upload_alt" unicode="" horiz-adv-x="1664" +d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 +t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" /> + <glyph glyph-name="lemon" unicode="" +d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 +q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 +q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 +q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -13 2 -25t3.5 -16.5t7.5 -20.5t8 -20q16 -40 25 -118.5t9 -136.5z" /> + <glyph glyph-name="phone" unicode="" horiz-adv-x="1408" +d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -53 3.5t-57.5 12.5t-47 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-127 79 -264 216t-216 264q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47t-12.5 57.5t-3.5 53q0 92 51 186 +q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174q2 -1 19 -11.5t24 -14 +t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" /> + <glyph glyph-name="check_empty" unicode="" horiz-adv-x="1408" +d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 +q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="bookmark_empty" unicode="" horiz-adv-x="1280" +d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 +q0 34 19.5 62t52.5 41q21 9 44 9h1048z" /> + <glyph glyph-name="phone_sign" unicode="" +d="M1280 343q0 11 -2 16t-18 16.5t-40.5 25t-47.5 26.5t-45.5 25t-28.5 15q-5 3 -19 13t-25 15t-21 5q-15 0 -36.5 -20.5t-39.5 -45t-38.5 -45t-33.5 -20.5q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170 126.5t-127 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5 +t-3.5 16.5q0 13 20.5 33.5t45 38.5t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5 +t320.5 -216.5q6 -2 30 -11t33 -12.5t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z +" /> + <glyph glyph-name="twitter" unicode="" horiz-adv-x="1664" +d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 +q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" /> + <glyph glyph-name="facebook" unicode="" horiz-adv-x="1024" +d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" /> + <glyph glyph-name="github" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24 +q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5 +t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12 +q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z +M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" /> + <glyph glyph-name="unlock" unicode="" horiz-adv-x="1664" +d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 +t316.5 -131.5t131.5 -316.5z" /> + <glyph glyph-name="credit_card" unicode="" horiz-adv-x="1920" +d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 +q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" /> + <glyph glyph-name="rss" unicode="" horiz-adv-x="1408" +d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 +t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 +q187 -186 294 -425.5t120 -501.5z" /> + <glyph glyph-name="hdd" unicode="" +d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 +h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 +l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" /> + <glyph glyph-name="bullhorn" unicode="" horiz-adv-x="1792" +d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 +t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" /> + <glyph glyph-name="bell" unicode="" horiz-adv-x="1792" +d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z +M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 +t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" /> + <glyph glyph-name="certificate" unicode="" +d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 +l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 +l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" /> + <glyph glyph-name="hand_right" unicode="" horiz-adv-x="1792" +d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 +q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 +q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 +t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" /> + <glyph glyph-name="hand_left" unicode="" horiz-adv-x="1792" +d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-8 9 -12 14q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576q-50 0 -89 -38.5 +t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45z +M1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128q0 122 81.5 189t206.5 67 +q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="hand_up" unicode="" +d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 +q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 +t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 +q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" /> + <glyph glyph-name="hand_down" unicode="" +d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 +t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 +q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 +q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" /> + <glyph glyph-name="circle_arrow_left" unicode="" +d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="circle_arrow_right" unicode="" +d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="circle_arrow_up" unicode="" +d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="circle_arrow_down" unicode="" +d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="globe" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 +q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 11t-9.5 10q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 +q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 +q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 +t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-4 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 +q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 +q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 +t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 +t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10.5t17 -19.5q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 +q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 +q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 +q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 +t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q8 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 +q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 +q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" /> + <glyph glyph-name="wrench" unicode="" horiz-adv-x="1664" +d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 +t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" /> + <glyph glyph-name="tasks" unicode="" horiz-adv-x="1792" +d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 +t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" /> + <glyph glyph-name="filter" unicode="" horiz-adv-x="1408" +d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" /> + <glyph glyph-name="briefcase" unicode="" horiz-adv-x="1792" +d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 +t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" /> + <glyph glyph-name="fullscreen" unicode="" +d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 +l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z +" /> + <glyph glyph-name="group" unicode="" horiz-adv-x="1920" +d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 +t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 +t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 +t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" /> + <glyph glyph-name="link" unicode="" horiz-adv-x="1664" +d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 +l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 +t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 +q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" /> + <glyph glyph-name="cloud" unicode="" horiz-adv-x="1920" +d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z +" /> + <glyph glyph-name="beaker" unicode="" horiz-adv-x="1664" +d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" /> + <glyph glyph-name="cut" unicode="" horiz-adv-x="1792" +d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 +q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 +q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 +q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 +q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" /> + <glyph glyph-name="copy" unicode="" horiz-adv-x="1792" +d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 +h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" /> + <glyph glyph-name="paper_clip" unicode="" horiz-adv-x="1408" +d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 +l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 +z" /> + <glyph glyph-name="save" unicode="" +d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 +h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" /> + <glyph glyph-name="sign_blank" unicode="" +d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="reorder" unicode="" +d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 +t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> + <glyph glyph-name="ul" unicode="" horiz-adv-x="1792" +d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 +t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z +M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="ol" unicode="" horiz-adv-x="1792" +d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 +q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 +t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 121.5t0.5 121.5v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216 +q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" /> + <glyph glyph-name="strikethrough" unicode="" horiz-adv-x="1792" +d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 98 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 +l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -56 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 +l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" /> + <glyph glyph-name="underline" unicode="" +d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 +q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 +q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 +q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" /> + <glyph glyph-name="table" unicode="" horiz-adv-x="1664" +d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 +v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 +q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 +q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 +z" /> + <glyph glyph-name="magic" unicode="" horiz-adv-x="1664" +d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 +l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" /> + <glyph glyph-name="truck" unicode="" horiz-adv-x="1792" +d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 +t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 +t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" /> + <glyph glyph-name="pinterest" unicode="" +d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 +q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 +q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="pinterest_sign" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 +t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 +t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" /> + <glyph glyph-name="google_plus_sign" unicode="" +d="M917 631q0 26 -6 64h-362v-132h217q-3 -24 -16.5 -50t-37.5 -53t-66.5 -44.5t-96.5 -17.5q-99 0 -169 71t-70 171t70 171t169 71q92 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585 +h109v110h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="google_plus" unicode="" horiz-adv-x="2304" +d="M1437 623q0 -208 -87 -370.5t-248 -254t-369 -91.5q-149 0 -285 58t-234 156t-156 234t-58 285t58 285t156 234t234 156t285 58q286 0 491 -192l-199 -191q-117 113 -292 113q-123 0 -227.5 -62t-165.5 -168.5t-61 -232.5t61 -232.5t165.5 -168.5t227.5 -62 +q83 0 152.5 23t114.5 57.5t78.5 78.5t49 83t21.5 74h-416v252h692q12 -63 12 -122zM2304 745v-210h-209v-209h-210v209h-209v210h209v209h210v-209h209z" /> + <glyph glyph-name="money" unicode="" horiz-adv-x="1920" +d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 +v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" /> + <glyph glyph-name="caret_down" unicode="" horiz-adv-x="1024" +d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> + <glyph glyph-name="caret_up" unicode="" horiz-adv-x="1024" +d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="caret_left" unicode="" horiz-adv-x="640" +d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" /> + <glyph glyph-name="caret_right" unicode="" horiz-adv-x="640" +d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="columns" unicode="" horiz-adv-x="1664" +d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" /> + <glyph glyph-name="sort" unicode="" horiz-adv-x="1024" +d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="sort_down" unicode="" horiz-adv-x="1024" +d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" /> + <glyph glyph-name="sort_up" unicode="" horiz-adv-x="1024" +d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" /> + <glyph glyph-name="envelope_alt" unicode="" horiz-adv-x="1792" +d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 +q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" /> + <glyph glyph-name="linkedin" unicode="" +d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 +q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" /> + <glyph glyph-name="undo" unicode="" +d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 +t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" /> + <glyph glyph-name="legal" unicode="" horiz-adv-x="1792" +d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 +t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 +q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 +q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" /> + <glyph glyph-name="dashboard" unicode="" horiz-adv-x="1792" +d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 +t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 +t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 +q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="comment_alt" unicode="" horiz-adv-x="1792" +d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 +q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 +t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> + <glyph glyph-name="comments_alt" unicode="" horiz-adv-x="1792" +d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 +t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 +t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 +q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" /> + <glyph glyph-name="bolt" unicode="" horiz-adv-x="896" +d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" /> + <glyph glyph-name="sitemap" unicode="" horiz-adv-x="1792" +d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 +q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 +z" /> + <glyph glyph-name="umbrella" unicode="" horiz-adv-x="1664" +d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 +q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 +q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" /> + <glyph glyph-name="paste" unicode="" horiz-adv-x="1792" +d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 +h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" /> + <glyph glyph-name="light_bulb" unicode="" horiz-adv-x="1024" +d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 +q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 +q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 +t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" /> + <glyph glyph-name="exchange" unicode="" horiz-adv-x="1792" +d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 +q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" /> + <glyph glyph-name="cloud_download" unicode="" horiz-adv-x="1920" +d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 +q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> + <glyph glyph-name="cloud_upload" unicode="" horiz-adv-x="1920" +d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 +q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" /> + <glyph glyph-name="user_md" unicode="" horiz-adv-x="1408" +d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 +t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 +t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 +t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="stethoscope" unicode="" horiz-adv-x="1408" +d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 +t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 +t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" /> + <glyph glyph-name="suitcase" unicode="" horiz-adv-x="1792" +d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 +t66 -158z" /> + <glyph glyph-name="bell_alt" unicode="" horiz-adv-x="1792" +d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 +t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" /> + <glyph glyph-name="coffee" unicode="" horiz-adv-x="1920" +d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 +t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="food" unicode="" horiz-adv-x="1408" +d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 +t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" /> + <glyph glyph-name="file_text_alt" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 +q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" /> + <glyph glyph-name="building" unicode="" horiz-adv-x="1408" +d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" /> + <glyph glyph-name="hospital" unicode="" horiz-adv-x="1408" +d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z +M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 +t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 +v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" /> + <glyph glyph-name="ambulance" unicode="" horiz-adv-x="1920" +d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 +t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 +q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="medkit" unicode="" horiz-adv-x="1792" +d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 +q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" /> + <glyph glyph-name="fighter_jet" unicode="" horiz-adv-x="1920" +d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 +q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q128 -28 200 -52t80 -34z" /> + <glyph glyph-name="beer" unicode="" horiz-adv-x="1664" +d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" /> + <glyph glyph-name="h_sign" unicode="" +d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="f0fe" unicode="" +d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="double_angle_left" unicode="" horiz-adv-x="1024" +d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 +t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" /> + <glyph glyph-name="double_angle_right" unicode="" horiz-adv-x="1024" +d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 +l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="double_angle_up" unicode="" horiz-adv-x="1152" +d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 +q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="double_angle_down" unicode="" horiz-adv-x="1152" +d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 +t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> + <glyph glyph-name="angle_left" unicode="" horiz-adv-x="640" +d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> + <glyph glyph-name="angle_right" unicode="" horiz-adv-x="640" +d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="angle_up" unicode="" horiz-adv-x="1152" +d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" /> + <glyph glyph-name="angle_down" unicode="" horiz-adv-x="1152" +d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" /> + <glyph glyph-name="desktop" unicode="" horiz-adv-x="1920" +d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 +t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="laptop" unicode="" horiz-adv-x="1920" +d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z +M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" /> + <glyph glyph-name="tablet" unicode="" horiz-adv-x="1152" +d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 +q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" /> + <glyph glyph-name="mobile_phone" unicode="" horiz-adv-x="768" +d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 +q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" /> + <glyph glyph-name="circle_blank" unicode="" +d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 +t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="quote_left" unicode="" horiz-adv-x="1664" +d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z +M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" /> + <glyph glyph-name="quote_right" unicode="" horiz-adv-x="1664" +d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 +v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" /> + <glyph glyph-name="spinner" unicode="" horiz-adv-x="1792" +d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 +t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z +M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5 +q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" /> + <glyph glyph-name="circle" unicode="" +d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="reply" unicode="" horiz-adv-x="1792" +d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 +l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" /> + <glyph glyph-name="github_alt" unicode="" horiz-adv-x="1664" +d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 +q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 +t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 +q0 -87 -27 -168q136 -160 136 -398z" /> + <glyph glyph-name="folder_close_alt" unicode="" horiz-adv-x="1664" +d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 +q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" /> + <glyph glyph-name="folder_open_alt" unicode="" horiz-adv-x="1920" +d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 +v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z +" /> + <glyph glyph-name="expand_alt" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="collapse_alt" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="smile" unicode="" +d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 +t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 +t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="frown" unicode="" +d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 +t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 +t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="meh" unicode="" +d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 +t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="gamepad" unicode="" horiz-adv-x="1920" +d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 +t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 +t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" /> + <glyph glyph-name="keyboard" unicode="" horiz-adv-x="1920" +d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 +h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 +h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 +q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 +h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="flag_alt" unicode="" horiz-adv-x="1792" +d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 +h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 +q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> + <glyph glyph-name="flag_checkered" unicode="" horiz-adv-x="1792" +d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 +q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 +q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 +q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" /> + <glyph glyph-name="terminal" unicode="" horiz-adv-x="1664" +d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 +t9 -23z" /> + <glyph glyph-name="code" unicode="" horiz-adv-x="1920" +d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 +l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" /> + <glyph glyph-name="reply_all" unicode="" horiz-adv-x="1792" +d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 +q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" /> + <glyph glyph-name="star_half_empty" unicode="" horiz-adv-x="1664" +d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 +l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" /> + <glyph glyph-name="location_arrow" unicode="" horiz-adv-x="1408" +d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" /> + <glyph glyph-name="crop" unicode="" horiz-adv-x="1664" +d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 +v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" /> + <glyph glyph-name="code_fork" unicode="" horiz-adv-x="1024" +d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 +q-2 -287 -226 -414q-67 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 +q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" /> + <glyph glyph-name="unlink" unicode="" horiz-adv-x="1664" +d="M439 265l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 +q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 +l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 +t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> + <glyph glyph-name="question" unicode="" horiz-adv-x="1024" +d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 +t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" /> + <glyph glyph-name="_279" unicode="" horiz-adv-x="640" +d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 +q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" /> + <glyph glyph-name="exclamation" unicode="" horiz-adv-x="640" +d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" /> + <glyph glyph-name="superscript" unicode="" +d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z +M1534 846v-206h-514l-3 27q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5 +t-65.5 -51.5t-30.5 -63h232v80h126z" /> + <glyph glyph-name="subscript" unicode="" +d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z +M1536 -50v-206h-514l-4 27q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73 +h232v80h126z" /> + <glyph glyph-name="_283" unicode="" horiz-adv-x="1920" +d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" /> + <glyph glyph-name="puzzle_piece" unicode="" horiz-adv-x="1664" +d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 +t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 +q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 +q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" /> + <glyph glyph-name="microphone" unicode="" horiz-adv-x="1152" +d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 +t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" /> + <glyph glyph-name="microphone_off" unicode="" horiz-adv-x="1408" +d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 +q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 +t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" /> + <glyph glyph-name="shield" unicode="" horiz-adv-x="1280" +d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 +t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" /> + <glyph glyph-name="calendar_empty" unicode="" horiz-adv-x="1664" +d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 +q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="fire_extinguisher" unicode="" horiz-adv-x="1408" +d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 +q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 +q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" /> + <glyph glyph-name="rocket" unicode="" horiz-adv-x="1664" +d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 +q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" /> + <glyph glyph-name="maxcdn" unicode="" horiz-adv-x="1792" +d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" /> + <glyph glyph-name="chevron_sign_left" unicode="" +d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="chevron_sign_right" unicode="" +d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="chevron_sign_up" unicode="" +d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="chevron_sign_down" unicode="" +d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 +t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="html5" unicode="" horiz-adv-x="1408" +d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" /> + <glyph glyph-name="css3" unicode="" horiz-adv-x="1792" +d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" /> + <glyph glyph-name="anchor" unicode="" horiz-adv-x="1792" +d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 +q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 +t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" /> + <glyph glyph-name="unlock_alt" unicode="" horiz-adv-x="1152" +d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 +v-320h736z" /> + <glyph glyph-name="bullseye" unicode="" +d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 +t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 +q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="ellipsis_horizontal" unicode="" horiz-adv-x="1408" +d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> + <glyph glyph-name="ellipsis_vertical" unicode="" horiz-adv-x="384" +d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 +q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" /> + <glyph glyph-name="_303" unicode="" +d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 233 -176.5 396.5t-396.5 176.5q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128 +q13 0 23 10t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="play_sign" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 +q16 -8 32 -8q17 0 32 9z" /> + <glyph glyph-name="ticket" unicode="" horiz-adv-x="1792" +d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 +t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" /> + <glyph glyph-name="minus_sign_alt" unicode="" +d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 +t84.5 -203.5z" /> + <glyph glyph-name="check_minus" unicode="" horiz-adv-x="1408" +d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 +t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="level_up" unicode="" horiz-adv-x="1024" +d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" /> + <glyph glyph-name="level_down" unicode="" horiz-adv-x="1024" +d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" /> + <glyph glyph-name="check_sign" unicode="" +d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 +t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="edit_sign" unicode="" +d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 +v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_312" unicode="" +d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 +q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="share_sign" unicode="" +d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q11 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 +t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="compass" unicode="" +d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="collapse" unicode="" +d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 +v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="collapse_top" unicode="" +d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_317" unicode="" +d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 +t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="eur" unicode="" horiz-adv-x="1024" +d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 +t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 +l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" /> + <glyph glyph-name="gbp" unicode="" horiz-adv-x="1024" +d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 +q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" /> + <glyph glyph-name="usd" unicode="" horiz-adv-x="1024" +d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 +t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 +t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 +t53 -63.5t31.5 -76.5t13 -94z" /> + <glyph glyph-name="inr" unicode="" horiz-adv-x="898" +d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 +q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" /> + <glyph glyph-name="jpy" unicode="" horiz-adv-x="1027" +d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 +l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" /> + <glyph glyph-name="rub" unicode="" horiz-adv-x="1280" +d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 +q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" /> + <glyph glyph-name="krw" unicode="" horiz-adv-x="1792" +d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 +t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 +q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" /> + <glyph glyph-name="btc" unicode="" horiz-adv-x="1280" +d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 +l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 +t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" /> + <glyph glyph-name="file" unicode="" +d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" /> + <glyph glyph-name="file_text" unicode="" +d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 +q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" /> + <glyph glyph-name="sort_by_alphabet" unicode="" horiz-adv-x="1664" +d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 +v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 +l230 -662h70z" /> + <glyph glyph-name="_329" unicode="" horiz-adv-x="1664" +d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 +v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 +v119h121z" /> + <glyph glyph-name="sort_by_attributes" unicode="" horiz-adv-x="1792" +d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 +q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 +q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" /> + <glyph glyph-name="sort_by_attributes_alt" unicode="" horiz-adv-x="1792" +d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 +q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 +q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" /> + <glyph glyph-name="sort_by_order" unicode="" +d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 +zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 +t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" /> + <glyph glyph-name="sort_by_order_alt" unicode="" +d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 +t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 +q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" /> + <glyph glyph-name="_334" unicode="" horiz-adv-x="1664" +d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 +q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 +t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" /> + <glyph glyph-name="_335" unicode="" horiz-adv-x="1664" +d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 +t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 +t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" /> + <glyph glyph-name="youtube_sign" unicode="" +d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 17 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 +q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 +q21 -29 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 +q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78q7 -23 23 -69l24 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38 +q-51 0 -78 -38q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5 +h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="youtube" unicode="" +d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 +q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 +q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 +q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-38 -51 -106 -51q-67 0 -105 51 +q-28 38 -28 118v175q0 80 28 117q38 51 105 51q68 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" /> + <glyph glyph-name="xing" unicode="" horiz-adv-x="1408" +d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 +q25 45 64 45h241q22 0 31 -15z" /> + <glyph glyph-name="xing_sign" unicode="" +d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 +l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="youtube_play" unicode="" horiz-adv-x="1792" +d="M711 408l484 250l-484 253v-503zM896 1270q168 0 324.5 -4.5t229.5 -9.5l73 -4q1 0 17 -1.5t23 -3t23.5 -4.5t28.5 -8t28 -13t31 -19.5t29 -26.5q6 -6 15.5 -18.5t29 -58.5t26.5 -101q8 -64 12.5 -136.5t5.5 -113.5v-40v-136q1 -145 -18 -290q-7 -55 -25 -99.5t-32 -61.5 +l-14 -17q-14 -15 -29 -26.5t-31 -19t-28 -12.5t-28.5 -8t-24 -4.5t-23 -3t-16.5 -1.5q-251 -19 -627 -19q-207 2 -359.5 6.5t-200.5 7.5l-49 4l-36 4q-36 5 -54.5 10t-51 21t-56.5 41q-6 6 -15.5 18.5t-29 58.5t-26.5 101q-8 64 -12.5 136.5t-5.5 113.5v40v136 +q-1 145 18 290q7 55 25 99.5t32 61.5l14 17q14 15 29 26.5t31 19.5t28 13t28.5 8t23.5 4.5t23 3t17 1.5q251 18 627 18z" /> + <glyph glyph-name="dropbox" unicode="" horiz-adv-x="1792" +d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" /> + <glyph glyph-name="stackexchange" unicode="" +d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" /> + <glyph glyph-name="instagram" unicode="" +d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270 +q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5 +t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317 +q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" /> + <glyph glyph-name="flickr" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 +t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" /> + <glyph glyph-name="adn" unicode="" +d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="f171" unicode="" horiz-adv-x="1408" +d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 +t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 +t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 +t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" /> + <glyph glyph-name="bitbucket_sign" unicode="" +d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 +t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z +M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 +v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="tumblr" unicode="" horiz-adv-x="1024" +d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 +q78 2 134 29z" /> + <glyph glyph-name="tumblr_sign" unicode="" +d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z +M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="long_arrow_down" unicode="" horiz-adv-x="768" +d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" /> + <glyph glyph-name="long_arrow_up" unicode="" horiz-adv-x="768" +d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" /> + <glyph glyph-name="long_arrow_left" unicode="" horiz-adv-x="1792" +d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" /> + <glyph glyph-name="long_arrow_right" unicode="" horiz-adv-x="1792" +d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" /> + <glyph glyph-name="apple" unicode="" horiz-adv-x="1408" +d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q113 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 +q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" /> + <glyph glyph-name="windows" unicode="" horiz-adv-x="1664" +d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" /> + <glyph glyph-name="android" unicode="" horiz-adv-x="1408" +d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 +t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 +h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" /> + <glyph glyph-name="linux" unicode="" +d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-10 -11 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z +M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 +q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 +q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 +t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 +q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 +q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18q-2 -1 -4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 +q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 +q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-6 0 -8 -2t0 -4 +t5 -3q14 -4 18 -31q0 -3 8 2q2 2 2 3zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5 +t-30 -18.5t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43 +q-19 4 -51 9.5t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49 +t-14 -48q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54 +q110 143 124 195q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5 +t-40.5 -33.5t-61 -14q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5 +t15.5 47.5q1 -31 8 -56.5t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" /> + <glyph glyph-name="dribble" unicode="" +d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 +t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 +q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -5 6.5 -17t7.5 -17q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 +t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="skype" unicode="" +d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 +t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 +q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 +q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" /> + <glyph glyph-name="foursquare" unicode="" horiz-adv-x="1280" +d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z +M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 +l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" /> + <glyph glyph-name="trello" unicode="" +d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 +q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" /> + <glyph glyph-name="female" unicode="" horiz-adv-x="1280" +d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 +q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="male" unicode="" horiz-adv-x="1024" +d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z +M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="gittip" unicode="" +d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="sun" unicode="" horiz-adv-x="1792" +d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 +l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 +q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" /> + <glyph glyph-name="_366" unicode="" +d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 +t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" /> + <glyph glyph-name="archive" unicode="" horiz-adv-x="1792" +d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 +q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" /> + <glyph glyph-name="bug" unicode="" horiz-adv-x="1664" +d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 +q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 +t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" /> + <glyph glyph-name="vk" unicode="" horiz-adv-x="1920" +d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-40 -51 -55 -72t-30.5 -49.5t-12 -42t13 -34.5t32.5 -43t57 -53q4 -2 5 -4q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 +t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 +q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q16 19 38 30q53 26 239 24 +q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 +q39 5 64 -2.5t31 -16.5z" /> + <glyph glyph-name="weibo" unicode="" horiz-adv-x="1792" +d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 +q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 +q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 +q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z +M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" /> + <glyph glyph-name="renren" unicode="" +d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 +q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" /> + <glyph glyph-name="_372" unicode="" horiz-adv-x="1408" +d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 +t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 +t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -4 1 -50t-1 -72q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 +t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" /> + <glyph glyph-name="stack_exchange" unicode="" horiz-adv-x="1280" +d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z +" /> + <glyph glyph-name="_374" unicode="" +d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 +t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="arrow_circle_alt_left" unicode="" +d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 +t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_376" unicode="" +d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z +M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="dot_circle_alt" unicode="" +d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 +t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_378" unicode="" horiz-adv-x="1664" +d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 +q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 17 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" /> + <glyph glyph-name="vimeo_square" unicode="" +d="M1292 898q10 216 -161 222q-231 8 -312 -261q44 19 82 19q85 0 74 -96q-4 -57 -74 -167t-105 -110q-43 0 -82 169q-13 54 -45 255q-30 189 -160 177q-59 -7 -164 -100l-81 -72l-81 -72l52 -67q76 52 87 52q57 0 107 -179q15 -55 45 -164.5t45 -164.5q68 -179 164 -179 +q157 0 383 294q220 283 226 444zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_380" unicode="" horiz-adv-x="1152" +d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 +q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> + <glyph glyph-name="plus_square_o" unicode="" horiz-adv-x="1408" +d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 +q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_382" unicode="" horiz-adv-x="2176" +d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 +t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 +q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" /> + <glyph glyph-name="_383" unicode="" horiz-adv-x="1664" +d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 +q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 +t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" /> + <glyph glyph-name="_384" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 +q-47 32 -142 92.5t-142 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 +t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" /> + <glyph glyph-name="_385" unicode="" horiz-adv-x="1792" +d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 +t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 +t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 +t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 +t273 -182.5t331.5 -68z" /> + <glyph glyph-name="_386" unicode="" horiz-adv-x="1792" +d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" /> + <glyph glyph-name="_387" unicode="" horiz-adv-x="2048" +d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 +q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" /> + <glyph glyph-name="_388" unicode="" horiz-adv-x="2304" +d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 +q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" /> + <glyph glyph-name="_389" unicode="" +d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q44 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 +q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" /> + <glyph glyph-name="uniF1A0" unicode="" +d="M768 750h725q12 -67 12 -128q0 -217 -91 -387.5t-259.5 -266.5t-386.5 -96q-157 0 -299 60.5t-245 163.5t-163.5 245t-60.5 299t60.5 299t163.5 245t245 163.5t299 60.5q300 0 515 -201l-209 -201q-123 119 -306 119q-129 0 -238.5 -65t-173.5 -176.5t-64 -243.5 +t64 -243.5t173.5 -176.5t238.5 -65q87 0 160 24t120 60t82 82t51.5 87t22.5 78h-436v264z" /> + <glyph glyph-name="f1a1" unicode="" horiz-adv-x="1792" +d="M1095 369q16 -16 0 -31q-62 -62 -199 -62t-199 62q-16 15 0 31q6 6 15 6t15 -6q48 -49 169 -49q120 0 169 49q6 6 15 6t15 -6zM788 550q0 -37 -26 -63t-63 -26t-63.5 26t-26.5 63q0 38 26.5 64t63.5 26t63 -26.5t26 -63.5zM1183 550q0 -37 -26.5 -63t-63.5 -26t-63 26 +t-26 63t26 63.5t63 26.5t63.5 -26t26.5 -64zM1434 670q0 49 -35 84t-85 35t-86 -36q-130 90 -311 96l63 283l200 -45q0 -37 26 -63t63 -26t63.5 26.5t26.5 63.5t-26.5 63.5t-63.5 26.5q-54 0 -80 -50l-221 49q-19 5 -25 -16l-69 -312q-180 -7 -309 -97q-35 37 -87 37 +q-50 0 -85 -35t-35 -84q0 -35 18.5 -64t49.5 -44q-6 -27 -6 -56q0 -142 140 -243t337 -101q198 0 338 101t140 243q0 32 -7 57q30 15 48 43.5t18 63.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191 +t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_392" unicode="" +d="M939 407q13 -13 0 -26q-53 -53 -171 -53t-171 53q-13 13 0 26q5 6 13 6t13 -6q42 -42 145 -42t145 42q5 6 13 6t13 -6zM676 563q0 -31 -23 -54t-54 -23t-54 23t-23 54q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1014 563q0 -31 -23 -54t-54 -23t-54 23t-23 54 +q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1229 666q0 42 -30 72t-73 30q-42 0 -73 -31q-113 78 -267 82l54 243l171 -39q1 -32 23.5 -54t53.5 -22q32 0 54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5q-48 0 -69 -43l-189 42q-17 5 -21 -13l-60 -268q-154 -6 -265 -83 +q-30 32 -74 32q-43 0 -73 -30t-30 -72q0 -30 16 -55t42 -38q-5 -25 -5 -48q0 -122 120 -208.5t289 -86.5q170 0 290 86.5t120 208.5q0 25 -6 49q25 13 40.5 37.5t15.5 54.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 +q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_393" unicode="" +d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 +v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 +t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="f1a4" unicode="" horiz-adv-x="1920" +d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 +v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" /> + <glyph glyph-name="_395" unicode="" +d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 +t84.5 -203.5z" /> + <glyph glyph-name="_396" unicode="" horiz-adv-x="2048" +d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 +v-369h123z" /> + <glyph glyph-name="_397" unicode="" +d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 +v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 +q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_398" unicode="" horiz-adv-x="2038" +d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 +q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 +q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 +q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 +t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 +q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 +t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 +t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" /> + <glyph glyph-name="_399" unicode="" +d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 +q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 +q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 +t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 +q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" /> + <glyph glyph-name="_400" unicode="" +d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z +M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 +t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 +q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 +t135.5 51q85 0 145 -60.5t60 -145.5z" /> + <glyph glyph-name="f1ab" unicode="" +d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 +q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 +q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z +M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 +q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q107 36 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 +q20 0 20 -21v-418z" /> + <glyph glyph-name="_402" unicode="" horiz-adv-x="1792" +d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 +l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 +t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 +q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 +q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" /> + <glyph glyph-name="_403" unicode="" +d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 +t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 +q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 +q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 +t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 +q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 +q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 +t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" /> + <glyph glyph-name="_404" unicode="" horiz-adv-x="1280" +d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68q29 28 68.5 28t67.5 -28l228 -228h368l228 228q28 28 68 28t68 -28q28 -29 28 -68.5t-28 -67.5zM864 1152 +q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="uniF1B1" unicode="" horiz-adv-x="1664" +d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 +q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 +q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 +t100.5 134t141.5 55.5z" /> + <glyph glyph-name="_406" unicode="" horiz-adv-x="768" +d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" /> + <glyph glyph-name="_407" unicode="" horiz-adv-x="1792" +d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z +" /> + <glyph glyph-name="_408" unicode="" horiz-adv-x="2304" +d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 +t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-4 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 +v-400l434 -186q36 -16 57 -48t21 -70z" /> + <glyph glyph-name="_409" unicode="" horiz-adv-x="2048" +d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 +q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 +q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" /> + <glyph glyph-name="_410" unicode="" +d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 +t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 +t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" /> + <glyph glyph-name="_411" unicode="" horiz-adv-x="1792" +d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 +q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 +q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" /> + <glyph glyph-name="_412" unicode="" +d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 +q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 +q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z +" /> + <glyph glyph-name="_413" unicode="" horiz-adv-x="1792" +d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 +l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 +t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 +q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" /> + <glyph glyph-name="_414" unicode="" horiz-adv-x="2048" +d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 +q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 +l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="_415" unicode="" horiz-adv-x="2048" +d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 +t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z +M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" /> + <glyph glyph-name="_416" unicode="" +d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 +q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" /> + <glyph glyph-name="_417" unicode="" +d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 +q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 +q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_418" unicode="" horiz-adv-x="1024" +d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" /> + <glyph glyph-name="_419" unicode="" horiz-adv-x="2304" +d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 +q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 +q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 +l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 +q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236 +q0 -11 -8 -19t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786 +q-13 2 -22 11t-9 22v899q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" /> + <glyph glyph-name="uniF1C0" unicode="" +d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 +t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 +t-103 128v128q0 69 103 128t280 93.5t385 34.5z" /> + <glyph glyph-name="uniF1C1" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 +q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 +q-1 1 -1 2q-1 2 -1 3q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" /> + <glyph glyph-name="_422" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4q0 3 -0.5 6.5t-1.5 8t-1 6.5q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5 +t-3.5 -21.5l-4 -21h-4l-2 21q-2 26 -7 46l-99 438h90v107h-300z" /> + <glyph glyph-name="_423" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 +h-290v-107h68l189 -272l-194 -283h-68z" /> + <glyph glyph-name="_424" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" /> + <glyph glyph-name="_425" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" /> + <glyph glyph-name="_426" unicode="" +d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 +v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 +q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" /> + <glyph glyph-name="_427" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 +q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" /> + <glyph glyph-name="_428" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" /> + <glyph glyph-name="_429" unicode="" +d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z +M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 +l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" /> + <glyph glyph-name="_430" unicode="" +d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 +q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" /> + <glyph glyph-name="_431" unicode="" horiz-adv-x="1792" +d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 +q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" /> + <glyph glyph-name="_432" unicode="" horiz-adv-x="2048" +d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 +q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 +t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97l93 -108q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5t-85 -189.5z" /> + <glyph glyph-name="_433" unicode="" horiz-adv-x="1792" +d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 +q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 +t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" /> + <glyph glyph-name="_434" unicode="" horiz-adv-x="1792" +d="M1760 640q0 -176 -68.5 -336t-184 -275.5t-275.5 -184t-336 -68.5t-336 68.5t-275.5 184t-184 275.5t-68.5 336q0 213 97 398.5t265 305.5t374 151v-228q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5 +t136.5 204t51 248.5q0 230 -145.5 406t-366.5 221v228q206 -31 374 -151t265 -305.5t97 -398.5z" /> + <glyph glyph-name="uniF1D0" unicode="" horiz-adv-x="1792" +d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 +t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 +t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 +q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" /> + <glyph glyph-name="uniF1D1" unicode="" horiz-adv-x="1792" +d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 +l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 +q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 +q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 +t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 +t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF1D2" unicode="" +d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 +q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 +q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 +q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_438" unicode="" horiz-adv-x="1792" +d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 +q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 +q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 +v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" /> + <glyph glyph-name="_439" unicode="" +d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="uniF1D5" unicode="" horiz-adv-x="1280" +d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 +t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 +t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" /> + <glyph glyph-name="uniF1D6" unicode="" horiz-adv-x="1792" +d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 +q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 +t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 +t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" /> + <glyph glyph-name="uniF1D7" unicode="" horiz-adv-x="2048" +d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 +q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 +q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 +q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" /> + <glyph glyph-name="_443" unicode="" horiz-adv-x="1792" +d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" /> + <glyph glyph-name="_444" unicode="" horiz-adv-x="1792" +d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 +l863 639l-478 -797z" /> + <glyph glyph-name="_445" unicode="" +d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 +t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 +t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_446" unicode="" +d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 +t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_447" unicode="" horiz-adv-x="1792" +d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 +t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 +t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 +q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 +q0 -26 -12 -48t-36 -22z" /> + <glyph glyph-name="_448" unicode="" horiz-adv-x="1280" +d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 +q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" /> + <glyph glyph-name="_449" unicode="" +d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 +q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" /> + <glyph glyph-name="uniF1E0" unicode="" +d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 +t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" /> + <glyph glyph-name="_451" unicode="" +d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 +t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_452" unicode="" horiz-adv-x="1792" +d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 +t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 +q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 +t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" /> + <glyph glyph-name="_453" unicode="" horiz-adv-x="1792" +d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 +l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" /> + <glyph glyph-name="_454" unicode="" horiz-adv-x="1792" +d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 +v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 +q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 +zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 +t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" /> + <glyph glyph-name="_455" unicode="" horiz-adv-x="1792" +d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z +M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_456" unicode="" horiz-adv-x="1792" +d="M1755 1083q37 -38 37 -90.5t-37 -90.5l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234 +l401 400q38 37 91 37t90 -37z" /> + <glyph glyph-name="_457" unicode="" horiz-adv-x="1792" +d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 +t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z +M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q4 -2 11.5 -7 +t10.5 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" /> + <glyph glyph-name="_458" unicode="" horiz-adv-x="1792" +d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" /> + <glyph glyph-name="_459" unicode="" +d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 +q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q71 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 +t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 +q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" /> + <glyph glyph-name="_460" unicode="" horiz-adv-x="2048" +d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 +t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" /> + <glyph glyph-name="_461" unicode="" horiz-adv-x="2048" +d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 +q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z +M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" /> + <glyph glyph-name="_462" unicode="" horiz-adv-x="1792" +d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 +t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 +t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 +t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z +M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 +h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_463" unicode="" +d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246 +q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598 +q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" /> + <glyph glyph-name="_464" unicode="" horiz-adv-x="1792" +d="M441 864q33 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640 +q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" /> + <glyph glyph-name="uniF1F0" unicode="" horiz-adv-x="2304" +d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 +q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 +q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_466" unicode="" horiz-adv-x="2304" +d="M1119 1195q-128 85 -281 85q-103 0 -197.5 -40.5t-162.5 -108.5t-108.5 -162t-40.5 -197q0 -104 40.5 -198t108.5 -162t162 -108.5t198 -40.5q153 0 281 85q-131 107 -178 265.5t0.5 316.5t177.5 265zM1152 1171q-126 -99 -172 -249.5t-0.5 -300.5t172.5 -249 +q127 99 172.5 249t-0.5 300.5t-172 249.5zM1185 1195q130 -107 177.5 -265.5t0.5 -317t-178 -264.5q128 -85 281 -85q104 0 198 40.5t162 108.5t108.5 162t40.5 198q0 103 -40.5 197t-108.5 162t-162.5 108.5t-197.5 40.5q-153 0 -281 -85zM1926 473h7v3h-17v-3h7v-17h3v17z +M1955 456h4v20h-5l-6 -13l-6 13h-5v-20h3v15l6 -13h4l5 13v-15zM1947 16v-2h-2h-3v3h3h2v-1zM1947 7h3l-4 5h2l1 1q1 1 1 3t-1 3l-1 1h-3h-6v-13h3v5h1zM685 75q0 19 11 31t30 12q18 0 29 -12.5t11 -30.5q0 -19 -11 -31t-29 -12q-19 0 -30 12t-11 31zM1158 119q30 0 35 -32 +h-70q5 32 35 32zM1514 75q0 19 11 31t29 12t29.5 -12.5t11.5 -30.5q0 -19 -11 -31t-30 -12q-18 0 -29 12t-11 31zM1786 75q0 18 11.5 30.5t29.5 12.5t29.5 -12.5t11.5 -30.5q0 -19 -11.5 -31t-29.5 -12t-29.5 12.5t-11.5 30.5zM1944 3q-2 0 -4 1q-1 0 -3 2t-2 3q-1 2 -1 4 +q0 3 1 4q0 2 2 4l1 1q2 0 2 1q2 1 4 1q3 0 4 -1l4 -2l2 -4v-1q1 -2 1 -3l-1 -1v-3t-1 -1l-1 -2q-2 -2 -4 -2q-1 -1 -4 -1zM599 7h30v85q0 24 -14.5 38.5t-39.5 15.5q-32 0 -47 -24q-14 24 -45 24q-24 0 -39 -20v16h-30v-135h30v75q0 36 33 36q30 0 30 -36v-75h29v75 +q0 36 33 36q30 0 30 -36v-75zM765 7h29v68v67h-29v-16q-17 20 -43 20q-29 0 -48 -20t-19 -51t19 -51t48 -20q28 0 43 20v-17zM943 48q0 34 -47 40l-14 2q-23 4 -23 14q0 15 25 15q23 0 43 -11l12 24q-22 14 -55 14q-26 0 -41 -12t-15 -32q0 -33 47 -39l13 -2q24 -4 24 -14 +q0 -17 -31 -17q-25 0 -45 14l-13 -23q25 -17 58 -17q29 0 45.5 12t16.5 32zM1073 14l-8 25q-13 -7 -26 -7q-19 0 -19 22v61h48v27h-48v41h-30v-41h-28v-27h28v-61q0 -50 47 -50q21 0 36 10zM1159 146q-29 0 -48 -20t-19 -51q0 -32 19.5 -51.5t49.5 -19.5q33 0 55 19l-14 22 +q-18 -15 -39 -15q-34 0 -41 33h101v12q0 32 -18 51.5t-46 19.5zM1318 146q-23 0 -35 -20v16h-30v-135h30v76q0 35 29 35q10 0 18 -4l9 28q-9 4 -21 4zM1348 75q0 -31 19.5 -51t52.5 -20q29 0 48 16l-14 24q-18 -13 -35 -12q-18 0 -29.5 12t-11.5 31t11.5 31t29.5 12 +q19 0 35 -12l14 24q-20 16 -48 16q-33 0 -52.5 -20t-19.5 -51zM1593 7h30v68v67h-30v-16q-15 20 -42 20q-29 0 -48.5 -20t-19.5 -51t19.5 -51t48.5 -20q28 0 42 20v-17zM1726 146q-23 0 -35 -20v16h-29v-135h29v76q0 35 29 35q10 0 18 -4l9 28q-8 4 -21 4zM1866 7h29v68v122 +h-29v-71q-15 20 -43 20t-47.5 -20.5t-19.5 -50.5t19.5 -50.5t47.5 -20.5q29 0 43 20v-17zM1944 27l-2 -1h-3q-2 -1 -4 -3q-3 -1 -3 -4q-1 -2 -1 -6q0 -3 1 -5q0 -2 3 -4q2 -2 4 -3t5 -1q4 0 6 1q0 1 2 2l2 1q1 1 3 4q1 2 1 5q0 4 -1 6q-1 1 -3 4q0 1 -2 2l-2 1q-1 0 -3 0.5 +t-3 0.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_467" unicode="" horiz-adv-x="2304" +d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 +q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 +v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 +q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 +t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" /> + <glyph glyph-name="f1f3" unicode="" horiz-adv-x="2304" +d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z +M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 +l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 +v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 +q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 +q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 +t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 +h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 +t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" /> + <glyph glyph-name="_469" unicode="" horiz-adv-x="2304" +d="M745 630q0 -37 -25.5 -61.5t-62.5 -24.5q-29 0 -46.5 16t-17.5 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM1530 779q0 -42 -22 -57t-66 -15l-32 -1l17 107q2 11 13 11h18q22 0 35 -2t25 -12.5t12 -30.5zM1881 630q0 -36 -25.5 -61t-61.5 -25q-29 0 -47 16 +t-18 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM513 801q0 59 -38.5 85.5t-100.5 26.5h-160q-19 0 -21 -19l-65 -408q-1 -6 3 -11t10 -5h76q20 0 22 19l18 110q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM822 489l41 261q1 6 -3 11t-10 5h-76 +q-14 0 -17 -33q-27 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q28 0 58 12t48 32q-4 -12 -4 -21q0 -16 13 -16h69q19 0 22 19zM1269 752q0 5 -4 9.5t-9 4.5h-77q-11 0 -18 -10l-106 -156l-44 150q-5 16 -22 16h-75q-5 0 -9 -4.5t-4 -9.5q0 -2 19.5 -59 +t42 -123t23.5 -70q-82 -112 -82 -120q0 -13 13 -13h77q11 0 18 10l255 368q2 2 2 7zM1649 801q0 59 -38.5 85.5t-100.5 26.5h-159q-20 0 -22 -19l-65 -408q-1 -6 3 -11t10 -5h82q12 0 16 13l18 116q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM1958 489 +l41 261q1 6 -3 11t-10 5h-76q-14 0 -17 -33q-26 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q29 0 59 12t47 32q0 -1 -2 -9t-2 -12q0 -16 13 -16h69q19 0 22 19zM2176 898v1q0 14 -13 14h-74q-11 0 -13 -11l-65 -416l-1 -2q0 -5 4 -9.5t10 -4.5h66 +q19 0 21 19zM392 764q-5 -35 -26 -46t-60 -11l-33 -1l17 107q2 11 13 11h19q40 0 58 -11.5t12 -48.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_470" unicode="" horiz-adv-x="2304" +d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 +q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 +q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 +q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 +q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_471" unicode="" horiz-adv-x="2048" +d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 +l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 +l418 363q10 8 23.5 7t21.5 -11z" /> + <glyph glyph-name="_472" unicode="" horiz-adv-x="2048" +d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 +q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 +q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" /> + <glyph glyph-name="_473" unicode="" horiz-adv-x="1408" +d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 +q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 +q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_474" unicode="" +d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 +t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 +t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_475" unicode="" +d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 +q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 +t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 +t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" /> + <glyph glyph-name="_476" unicode="" horiz-adv-x="1792" +d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 +t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" /> + <glyph glyph-name="f1fc" unicode="" horiz-adv-x="1792" +d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 +t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" /> + <glyph glyph-name="_478" unicode="" horiz-adv-x="1792" +d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11q24 0 44 -7t31 -15t33 -27q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5 +t47 37.5q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-24 0 -44 7t-31 15t-33 27q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38 +t-58 27t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448 +h256v448h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5 +q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" /> + <glyph glyph-name="_479" unicode="" horiz-adv-x="2048" +d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" /> + <glyph glyph-name="_480" unicode="" horiz-adv-x="1792" +d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_481" unicode="" horiz-adv-x="2048" +d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 +t9 -23z" /> + <glyph glyph-name="_482" unicode="" horiz-adv-x="1792" +d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 +q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 +t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 +q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" /> + <glyph glyph-name="_483" unicode="" +d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 +q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 +q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 +q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_484" unicode="" horiz-adv-x="2048" +d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 +t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 +t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" /> + <glyph glyph-name="_485" unicode="" horiz-adv-x="2048" +d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 +t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" /> + <glyph glyph-name="_486" unicode="" horiz-adv-x="2304" +d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 +q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 +q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 +q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" /> + <glyph glyph-name="_487" unicode="" +d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 +h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 +t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" /> + <glyph glyph-name="_488" unicode="" horiz-adv-x="2048" +d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 +q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 +q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" /> + <glyph glyph-name="_489" unicode="" horiz-adv-x="1280" +d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q17 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 +t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 +t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 +q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 +q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 +t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" /> + <glyph glyph-name="_490" unicode="" horiz-adv-x="2048" +d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 +q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 +t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 +t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" /> + <glyph glyph-name="_491" unicode="" +d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 +t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" /> + <glyph glyph-name="_492" unicode="" +d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 +q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 +q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" /> + <glyph glyph-name="_493" unicode="" +d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" /> + <glyph glyph-name="_494" unicode="" horiz-adv-x="2048" +d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 +q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5 +q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360l15 -6l188 199v347l-187 194q-13 -8 -29 -10zM986 1438 +h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13zM552 226h402l64 66 +l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224l213 -225zM1023 946 +l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196l-48 -227l130 227h-82 +zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" /> + <glyph glyph-name="f210" unicode="" +d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" /> + <glyph glyph-name="_496" unicode="" +d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 +q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" /> + <glyph glyph-name="f212" unicode="" horiz-adv-x="2048" +d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 +q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25 +q209 0 374 -102q172 107 374 102z" /> + <glyph glyph-name="_498" unicode="" horiz-adv-x="2048" +d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 +q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284 +q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" /> + <glyph glyph-name="_499" unicode="" +d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 +l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114 +v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z +M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378 +v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51 +h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5 +t-43 -34t-16.5 -53.5z" /> + <glyph glyph-name="_500" unicode="" horiz-adv-x="2048" +d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 +q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" /> + <glyph glyph-name="_501" unicode="" horiz-adv-x="2048" +d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126t-103.5 132.5t-108.5 126.5t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 +t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113 +t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5 +q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" /> + <glyph glyph-name="_502" unicode="" horiz-adv-x="1664" +d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 +t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 +q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> + <glyph glyph-name="_503" unicode="" horiz-adv-x="1664" +d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 +t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 +q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" /> + <glyph glyph-name="_504" unicode="" horiz-adv-x="2048" +d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 +l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" /> + <glyph glyph-name="_505" unicode="" horiz-adv-x="2048" +d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 +q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83 +q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314 +v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 +q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" /> + <glyph glyph-name="_506" unicode="" +d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 +t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5 +q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31 +t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" /> + <glyph glyph-name="_507" unicode="" horiz-adv-x="2304" +d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 +t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105 +l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226 +t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" /> + <glyph glyph-name="_508" unicode="" +d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 +q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384 +q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5 +t158.5 -65.5t65.5 -158.5z" /> + <glyph glyph-name="_509" unicode="" horiz-adv-x="1792" +d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 +q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124 +t127 -344z" /> + <glyph glyph-name="venus" unicode="" horiz-adv-x="1280" +d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 +q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" /> + <glyph glyph-name="_511" unicode="" +d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-382 -383q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5 +q203 0 359 -126l382 382h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_512" unicode="" horiz-adv-x="1280" +d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 +t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 +t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_513" unicode="" +d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 +q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 +t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_514" unicode="" horiz-adv-x="1792" +d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 +q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9 +t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5 +t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_515" unicode="" horiz-adv-x="1792" +d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 +t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391 +q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391 +q0 -226 -154 -391q103 -57 218 -57z" /> + <glyph glyph-name="_516" unicode="" horiz-adv-x="1920" +d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 +q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9 +t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128 +q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -28 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" /> + <glyph glyph-name="_517" unicode="" horiz-adv-x="2048" +d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 +t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9 +t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5 +t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" /> + <glyph glyph-name="_518" unicode="" +d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-213 -214l140 -140q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-140 141l-78 -79q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5 +t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5q203 0 359 -126l78 78l-172 172q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l172 -172l213 213h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 +t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_519" unicode="" horiz-adv-x="1280" +d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 +t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5 +t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_520" unicode="" horiz-adv-x="2048" +d="M1901 621q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-132q-24 -217 -187.5 -364.5t-384.5 -147.5q-167 0 -306 87t-212 236t-54 319q15 133 88 245.5 +t188 182t249 80.5q155 12 292 -52.5t224 -186t103 -271.5h132v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM576 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5 +t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_521" unicode="" horiz-adv-x="1280" +d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 +t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" /> + <glyph glyph-name="_522" unicode="" horiz-adv-x="1280" +d="M1024 576q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1152 576q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123 +t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5z" /> + <glyph glyph-name="_523" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="_524" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="_525" unicode="" +d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" /> + <glyph glyph-name="_526" unicode="" horiz-adv-x="1280" +d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 +l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5 +q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" /> + <glyph glyph-name="_527" unicode="" +d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 +t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233 +l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" /> + <glyph glyph-name="_528" unicode="" horiz-adv-x="1792" +d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 +q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" /> + <glyph glyph-name="_529" unicode="" horiz-adv-x="2048" +d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 +t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5 +t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" /> + <glyph glyph-name="_530" unicode="" horiz-adv-x="2048" +d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 +q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69 +t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" /> + <glyph glyph-name="_531" unicode="" horiz-adv-x="2048" +d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 +q-26 0 -45 -19t-19 -45v-384h1152z" /> + <glyph glyph-name="_532" unicode="" +d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" /> + <glyph glyph-name="_533" unicode="" +d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 +t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" /> + <glyph glyph-name="_534" unicode="" +d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 +t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" /> + <glyph glyph-name="_535" unicode="" horiz-adv-x="1792" +d="M597 1115v-1173q0 -25 -12.5 -42.5t-36.5 -17.5q-17 0 -33 8l-465 233q-21 10 -35.5 33.5t-14.5 46.5v1140q0 20 10 34t29 14q14 0 44 -15l511 -256q3 -3 3 -5zM661 1014l534 -866l-534 266v600zM1792 996v-1054q0 -25 -14 -40.5t-38 -15.5t-47 13l-441 220zM1789 1116 +q0 -3 -256.5 -419.5t-300.5 -487.5l-390 634l324 527q17 28 52 28q14 0 26 -6l541 -270q4 -2 4 -6z" /> + <glyph glyph-name="_536" unicode="" +d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1408v-1536h-1536v1536h1536z" /> + <glyph glyph-name="_537" unicode="" horiz-adv-x="2296" +d="M478 -139q-8 -16 -27 -34.5t-37 -25.5q-25 -9 -51.5 3.5t-28.5 31.5q-1 22 40 55t68 38q23 4 34 -21.5t2 -46.5zM1819 -139q7 -16 26 -34.5t38 -25.5q25 -9 51.5 3.5t27.5 31.5q2 22 -39.5 55t-68.5 38q-22 4 -33 -21.5t-2 -46.5zM1867 -30q13 -27 56.5 -59.5t77.5 -41.5 +q45 -13 82 4.5t37 50.5q0 46 -67.5 100.5t-115.5 59.5q-40 5 -63.5 -37.5t-6.5 -76.5zM428 -30q-13 -27 -56 -59.5t-77 -41.5q-45 -13 -82 4.5t-37 50.5q0 46 67.5 100.5t115.5 59.5q40 5 63 -37.5t6 -76.5zM1158 1094h1q-41 0 -76 -15q27 -8 44 -30.5t17 -49.5 +q0 -35 -27 -60t-65 -25q-52 0 -80 43q-5 -23 -5 -42q0 -74 56 -126.5t135 -52.5q80 0 136 52.5t56 126.5t-56 126.5t-136 52.5zM1462 1312q-99 109 -220.5 131.5t-245.5 -44.5q27 60 82.5 96.5t118 39.5t121.5 -17t99.5 -74.5t44.5 -131.5zM2212 73q8 -11 -11 -42 +q7 -23 7 -40q1 -56 -44.5 -112.5t-109.5 -91.5t-118 -37q-48 -2 -92 21.5t-66 65.5q-687 -25 -1259 0q-23 -41 -66.5 -65t-92.5 -22q-86 3 -179.5 80.5t-92.5 160.5q2 22 7 40q-19 31 -11 42q6 10 31 1q14 22 41 51q-7 29 2 38q11 10 39 -4q29 20 59 34q0 29 13 37 +q23 12 51 -16q35 5 61 -2q18 -4 38 -19v73q-11 0 -18 2q-53 10 -97 44.5t-55 87.5q-9 38 0 81q15 62 93 95q2 17 19 35.5t36 23.5t33 -7.5t19 -30.5h13q46 -5 60 -23q3 -3 5 -7q10 1 30.5 3.5t30.5 3.5q-15 11 -30 17q-23 40 -91 43q0 6 1 10q-62 2 -118.5 18.5t-84.5 47.5 +q-32 36 -42.5 92t-2.5 112q16 126 90 179q23 16 52 4.5t32 -40.5q0 -1 1.5 -14t2.5 -21t3 -20t5.5 -19t8.5 -10q27 -14 76 -12q48 46 98 74q-40 4 -162 -14l47 46q61 58 163 111q145 73 282 86q-20 8 -41 15.5t-47 14t-42.5 10.5t-47.5 11t-43 10q595 126 904 -139 +q98 -84 158 -222q85 -10 121 9h1q5 3 8.5 10t5.5 19t3 19.5t3 21.5l1 14q3 28 32 40t52 -5q73 -52 91 -178q7 -57 -3.5 -113t-42.5 -91q-28 -32 -83.5 -48.5t-115.5 -18.5v-10q-71 -2 -95 -43q-14 -5 -31 -17q11 -1 32 -3.5t30 -3.5q1 5 5 8q16 18 60 23h13q5 18 19 30t33 8 +t36 -23t19 -36q79 -32 93 -95q9 -40 1 -81q-12 -53 -56 -88t-97 -44q-10 -2 -17 -2q0 -49 -1 -73q20 15 38 19q26 7 61 2q28 28 51 16q14 -9 14 -37q33 -16 59 -34q27 13 38 4q10 -10 2 -38q28 -30 41 -51q23 8 31 -1zM1937 1025q0 -29 -9 -54q82 -32 112 -132 +q4 37 -9.5 98.5t-41.5 90.5q-20 19 -36 17t-16 -20zM1859 925q35 -42 47.5 -108.5t-0.5 -124.5q67 13 97 45q13 14 18 28q-3 64 -31 114.5t-79 66.5q-15 -15 -52 -21zM1822 921q-30 0 -44 1q42 -115 53 -239q21 0 43 3q16 68 1 135t-53 100zM258 839q30 100 112 132 +q-9 25 -9 54q0 18 -16.5 20t-35.5 -17q-28 -29 -41.5 -90.5t-9.5 -98.5zM294 737q29 -31 97 -45q-13 58 -0.5 124.5t47.5 108.5v0q-37 6 -52 21q-51 -16 -78.5 -66t-31.5 -115q9 -17 18 -28zM471 683q14 124 73 235q-19 -4 -55 -18l-45 -19v1q-46 -89 -20 -196q25 -3 47 -3z +M1434 644q8 -38 16.5 -108.5t11.5 -89.5q3 -18 9.5 -21.5t23.5 4.5q40 20 62 85.5t23 125.5q-24 2 -146 4zM1152 1285q-116 0 -199 -82.5t-83 -198.5q0 -117 83 -199.5t199 -82.5t199 82.5t83 199.5q0 116 -83 198.5t-199 82.5zM1380 646q-105 2 -211 0v1q-1 -27 2.5 -86 +t13.5 -66q29 -14 93.5 -14.5t95.5 10.5q9 3 11 39t-0.5 69.5t-4.5 46.5zM1112 447q8 4 9.5 48t-0.5 88t-4 63v1q-212 -3 -214 -3q-4 -20 -7 -62t0 -83t14 -46q34 -15 101 -16t101 10zM718 636q-16 -59 4.5 -118.5t77.5 -84.5q15 -8 24 -5t12 21q3 16 8 90t10 103 +q-69 -2 -136 -6zM591 510q3 -23 -34 -36q132 -141 271.5 -240t305.5 -154q172 49 310.5 146t293.5 250q-33 13 -30 34q0 2 0.5 3.5t1.5 3t1 2.5v1v-1q-17 2 -50 5.5t-48 4.5q-26 -90 -82 -132q-51 -38 -82 1q-5 6 -9 14q-7 13 -17 62q-2 -5 -5 -9t-7.5 -7t-8 -5.5t-9.5 -4 +l-10 -2.5t-12 -2l-12 -1.5t-13.5 -1t-13.5 -0.5q-106 -9 -163 11q-4 -17 -10 -26.5t-21 -15t-23 -7t-36 -3.5q-6 -1 -9 -1q-179 -17 -203 40q-2 -63 -56 -54q-47 8 -91 54q-12 13 -20 26q-17 29 -26 65q-58 -6 -87 -10q1 -2 4 -10zM507 -118q3 14 3 30q-17 71 -51 130 +t-73 70q-41 12 -101.5 -14.5t-104.5 -80t-39 -107.5q35 -53 100 -93t119 -42q51 -2 94 28t53 79zM510 53q23 -63 27 -119q195 113 392 174q-98 52 -180.5 120t-179.5 165q-6 -4 -29 -13q0 -1 -1 -4t-1 -5q31 -18 22 -37q-12 -23 -56 -34q-10 -13 -29 -24h-1q-2 -83 1 -150 +q19 -34 35 -73zM579 -113q532 -21 1145 0q-254 147 -428 196q-76 -35 -156 -57q-8 -3 -16 0q-65 21 -129 49q-208 -60 -416 -188h-1v-1q1 0 1 1zM1763 -67q4 54 28 120q14 38 33 71l-1 -1q3 77 3 153q-15 8 -30 25q-42 9 -56 33q-9 20 22 38q-2 4 -2 9q-16 4 -28 12 +q-204 -190 -383 -284q198 -59 414 -176zM2155 -90q5 54 -39 107.5t-104 80t-102 14.5q-38 -11 -72.5 -70.5t-51.5 -129.5q0 -16 3 -30q10 -49 53 -79t94 -28q54 2 119 42t100 93z" /> + <glyph glyph-name="_538" unicode="" horiz-adv-x="2304" +d="M1524 -25q0 -68 -48 -116t-116 -48t-116.5 48t-48.5 116t48.5 116.5t116.5 48.5t116 -48.5t48 -116.5zM775 -25q0 -68 -48.5 -116t-116.5 -48t-116 48t-48 116t48 116.5t116 48.5t116.5 -48.5t48.5 -116.5zM0 1469q57 -60 110.5 -104.5t121 -82t136 -63t166 -45.5 +t200 -31.5t250 -18.5t304 -9.5t372.5 -2.5q139 0 244.5 -5t181 -16.5t124 -27.5t71 -39.5t24 -51.5t-19.5 -64t-56.5 -76.5t-89.5 -91t-116 -104.5t-139 -119q-185 -157 -286 -247q29 51 76.5 109t94 105.5t94.5 98.5t83 91.5t54 80.5t13 70t-45.5 55.5t-116.5 41t-204 23.5 +t-304 5q-168 -2 -314 6t-256 23t-204.5 41t-159.5 51.5t-122.5 62.5t-91.5 66.5t-68 71.5t-50.5 69.5t-40 68t-36.5 59.5z" /> + <glyph glyph-name="_539" unicode="" horiz-adv-x="1792" +d="M896 1472q-169 0 -323 -66t-265.5 -177.5t-177.5 -265.5t-66 -323t66 -323t177.5 -265.5t265.5 -177.5t323 -66t323 66t265.5 177.5t177.5 265.5t66 323t-66 323t-177.5 265.5t-265.5 177.5t-323 66zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348 +t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM496 704q16 0 16 -16v-480q0 -16 -16 -16h-32q-16 0 -16 16v480q0 16 16 16h32zM896 640q53 0 90.5 -37.5t37.5 -90.5q0 -35 -17.5 -64t-46.5 -46v-114q0 -14 -9 -23 +t-23 -9h-64q-14 0 -23 9t-9 23v114q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5zM896 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM544 928v-96 +q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 93 65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5v-96q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 146 -103 249t-249 103t-249 -103t-103 -249zM1408 192v512q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-512 +q0 -26 19 -45t45 -19h896q26 0 45 19t19 45z" /> + <glyph glyph-name="_540" unicode="" horiz-adv-x="2304" +d="M1920 1024v-768h-1664v768h1664zM2048 448h128v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288zM2304 832v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113 +v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160q53 0 90.5 -37.5t37.5 -90.5z" /> + <glyph glyph-name="_541" unicode="" horiz-adv-x="2304" +d="M256 256v768h1280v-768h-1280zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 +h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_542" unicode="" horiz-adv-x="2304" +d="M256 256v768h896v-768h-896zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 +h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_543" unicode="" horiz-adv-x="2304" +d="M256 256v768h512v-768h-512zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9 +h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_544" unicode="" horiz-adv-x="2304" +d="M2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23 +v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" /> + <glyph glyph-name="_545" unicode="" horiz-adv-x="1280" +d="M1133 493q31 -30 14 -69q-17 -40 -59 -40h-382l201 -476q10 -25 0 -49t-34 -35l-177 -75q-25 -10 -49 0t-35 34l-191 452l-312 -312q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v1504q0 42 40 59q12 5 24 5q27 0 45 -19z" /> + <glyph glyph-name="_546" unicode="" horiz-adv-x="1024" +d="M832 1408q-320 0 -320 -224v-416h128v-128h-128v-544q0 -224 320 -224h64v-128h-64q-272 0 -384 146q-112 -146 -384 -146h-64v128h64q320 0 320 224v544h-128v128h128v416q0 224 -320 224h-64v128h64q272 0 384 -146q112 146 384 146h64v-128h-64z" /> + <glyph glyph-name="_547" unicode="" horiz-adv-x="2048" +d="M2048 1152h-128v-1024h128v-384h-384v128h-1280v-128h-384v384h128v1024h-128v384h384v-128h1280v128h384v-384zM1792 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 -128v128h-128v-128h128zM1664 0v128h128v1024h-128v128h-1280v-128h-128v-1024h128v-128 +h1280zM1920 -128v128h-128v-128h128zM1280 896h384v-768h-896v256h-384v768h896v-256zM512 512h640v512h-640v-512zM1536 256v512h-256v-384h-384v-128h640z" /> + <glyph glyph-name="_548" unicode="" horiz-adv-x="2304" +d="M2304 768h-128v-640h128v-384h-384v128h-896v-128h-384v384h128v128h-384v-128h-384v384h128v640h-128v384h384v-128h896v128h384v-384h-128v-128h384v128h384v-384zM2048 1024v-128h128v128h-128zM1408 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 256 +v128h-128v-128h128zM1536 384h-128v-128h128v128zM384 384h896v128h128v640h-128v128h-896v-128h-128v-640h128v-128zM896 -128v128h-128v-128h128zM2176 -128v128h-128v-128h128zM2048 128v640h-128v128h-384v-384h128v-384h-384v128h-384v-128h128v-128h896v128h128z" /> + <glyph glyph-name="_549" unicode="" +d="M1024 288v-416h-928q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68v-928h-416q-40 0 -68 -28t-28 -68zM1152 256h381q-15 -82 -65 -132l-184 -184q-50 -50 -132 -65v381z" /> + <glyph glyph-name="_550" unicode="" +d="M1400 256h-248v-248q29 10 41 22l185 185q12 12 22 41zM1120 384h288v896h-1280v-1280h896v288q0 40 28 68t68 28zM1536 1312v-1024q0 -40 -20 -88t-48 -76l-184 -184q-28 -28 -76 -48t-88 -20h-1024q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68 +z" /> + <glyph glyph-name="_551" unicode="" horiz-adv-x="2304" +d="M1951 538q0 -26 -15.5 -44.5t-38.5 -23.5q-8 -2 -18 -2h-153v140h153q10 0 18 -2q23 -5 38.5 -23.5t15.5 -44.5zM1933 751q0 -25 -15 -42t-38 -21q-3 -1 -15 -1h-139v129h139q3 0 8.5 -0.5t6.5 -0.5q23 -4 38 -21.5t15 -42.5zM728 587v308h-228v-308q0 -58 -38 -94.5 +t-105 -36.5q-108 0 -229 59v-112q53 -15 121 -23t109 -9l42 -1q328 0 328 217zM1442 403v113q-99 -52 -200 -59q-108 -8 -169 41t-61 142t61 142t169 41q101 -7 200 -58v112q-48 12 -100 19.5t-80 9.5l-28 2q-127 6 -218.5 -14t-140.5 -60t-71 -88t-22 -106t22 -106t71 -88 +t140.5 -60t218.5 -14q101 4 208 31zM2176 518q0 54 -43 88.5t-109 39.5v3q57 8 89 41.5t32 79.5q0 55 -41 88t-107 36q-3 0 -12 0.5t-14 0.5h-455v-510h491q74 0 121.5 36.5t47.5 96.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90 +t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_552" unicode="" horiz-adv-x="2304" +d="M858 295v693q-106 -41 -172 -135.5t-66 -211.5t66 -211.5t172 -134.5zM1362 641q0 117 -66 211.5t-172 135.5v-694q106 41 172 135.5t66 211.5zM1577 641q0 -159 -78.5 -294t-213.5 -213.5t-294 -78.5q-119 0 -227.5 46.5t-187 125t-125 187t-46.5 227.5q0 159 78.5 294 +t213.5 213.5t294 78.5t294 -78.5t213.5 -213.5t78.5 -294zM1960 634q0 139 -55.5 261.5t-147.5 205.5t-213.5 131t-252.5 48h-301q-176 0 -323.5 -81t-235 -230t-87.5 -335q0 -171 87 -317.5t236 -231.5t323 -85h301q129 0 251.5 50.5t214.5 135t147.5 202.5t55.5 246z +M2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_553" unicode="" horiz-adv-x="1792" +d="M1664 -96v1088q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5zM1792 992v-1088q0 -66 -47 -113t-113 -47h-1088q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113 +zM1408 1376v-160h-128v160q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h160v-128h-160q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113z" /> + <glyph glyph-name="_554" unicode="" horiz-adv-x="2304" +d="M1728 1088l-384 -704h768zM448 1088l-384 -704h768zM1269 1280q-14 -40 -45.5 -71.5t-71.5 -45.5v-1291h608q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1344q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h608v1291q-40 14 -71.5 45.5t-45.5 71.5h-491q-14 0 -23 9t-9 23v64 +q0 14 9 23t23 9h491q21 57 70 92.5t111 35.5t111 -35.5t70 -92.5h491q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-491zM1088 1264q33 0 56.5 23.5t23.5 56.5t-23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5zM2176 384q0 -73 -46.5 -131t-117.5 -91 +t-144.5 -49.5t-139.5 -16.5t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81zM896 384q0 -73 -46.5 -131t-117.5 -91t-144.5 -49.5t-139.5 -16.5 +t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81z" /> + <glyph glyph-name="_555" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-77 -29 -149 -92.5 +t-129.5 -152.5t-92.5 -210t-35 -253h1024q0 132 -35 253t-92.5 210t-129.5 152.5t-149 92.5q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" /> + <glyph glyph-name="_556" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -66 9 -128h1006q9 61 9 128zM1280 -128q0 130 -34 249.5t-90.5 208t-126.5 152t-146 94.5h-230q-76 -31 -146 -94.5t-126.5 -152t-90.5 -208t-34 -249.5h1024z" /> + <glyph glyph-name="_557" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -206 85 -384h854q85 178 85 384zM1223 192q-54 141 -145.5 241.5t-194.5 142.5h-230q-103 -42 -194.5 -142.5t-145.5 -241.5h910z" /> + <glyph glyph-name="_558" unicode="" +d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9 +t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-137 -51 -244 -196 +h700q-107 145 -244 196q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" /> + <glyph glyph-name="_559" unicode="" +d="M1504 -64q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472zM130 0q3 55 16 107t30 95t46 87t53.5 76t64.5 69.5t66 60t70.5 55t66.5 47.5t65 43q-43 28 -65 43t-66.5 47.5t-70.5 55t-66 60t-64.5 69.5t-53.5 76t-46 87 +t-30 95t-16 107h1276q-3 -55 -16 -107t-30 -95t-46 -87t-53.5 -76t-64.5 -69.5t-66 -60t-70.5 -55t-66.5 -47.5t-65 -43q43 -28 65 -43t66.5 -47.5t70.5 -55t66 -60t64.5 -69.5t53.5 -76t46 -87t30 -95t16 -107h-1276zM1504 1536q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9 +h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472z" /> + <glyph glyph-name="_560" unicode="" +d="M768 1152q-53 0 -90.5 -37.5t-37.5 -90.5v-128h-32v93q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-429l-32 30v172q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-224q0 -47 35 -82l310 -296q39 -39 39 -102q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v25 +q0 41 10 77l108 436q10 36 10 77v246q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-32h-32v125q0 40 -25 72.5t-64 40.5q-14 2 -23 2q-46 0 -79 -33t-33 -79v-128h-32v122q0 51 -32.5 89.5t-82.5 43.5q-5 1 -13 1zM768 1280q84 0 149 -50q57 34 123 34q59 0 111 -27 +t86 -76q27 7 59 7q100 0 170 -71.5t70 -171.5v-246q0 -51 -13 -108l-109 -436q-6 -24 -6 -71q0 -80 -56 -136t-136 -56h-640q-84 0 -138 58.5t-54 142.5l-308 296q-76 73 -76 175v224q0 99 70.5 169.5t169.5 70.5q11 0 16 -1q6 95 75.5 160t164.5 65q52 0 98 -21 +q72 69 174 69z" /> + <glyph glyph-name="_561" unicode="" horiz-adv-x="1792" +d="M880 1408q-46 0 -79 -33t-33 -79v-656h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528v-256l-154 205q-38 51 -102 51q-53 0 -90.5 -37.5t-37.5 -90.5q0 -43 26 -77l384 -512q38 -51 102 -51h688q34 0 61 22t34 56l76 405q5 32 5 59v498q0 46 -33 79t-79 33t-79 -33 +t-33 -79v-272h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528h-32v656q0 46 -33 79t-79 33zM880 1536q68 0 125.5 -35.5t88.5 -96.5q19 4 42 4q99 0 169.5 -70.5t70.5 -169.5v-17q105 6 180.5 -64t75.5 -175v-498q0 -40 -8 -83l-76 -404q-14 -79 -76.5 -131t-143.5 -52 +h-688q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 106 75 181t181 75q78 0 128 -34v434q0 99 70.5 169.5t169.5 70.5q23 0 42 -4q31 61 88.5 96.5t125.5 35.5z" /> + <glyph glyph-name="_562" unicode="" horiz-adv-x="1792" +d="M1073 -128h-177q-163 0 -226 141q-23 49 -23 102v5q-62 30 -98.5 88.5t-36.5 127.5q0 38 5 48h-261q-106 0 -181 75t-75 181t75 181t181 75h113l-44 17q-74 28 -119.5 93.5t-45.5 145.5q0 106 75 181t181 75q46 0 91 -17l628 -239h401q106 0 181 -75t75 -181v-668 +q0 -88 -54 -157.5t-140 -90.5l-339 -85q-92 -23 -186 -23zM1024 583l-155 -71l-163 -74q-30 -14 -48 -41.5t-18 -60.5q0 -46 33 -79t79 -33q26 0 46 10l338 154q-49 10 -80.5 50t-31.5 90v55zM1344 272q0 46 -33 79t-79 33q-26 0 -46 -10l-290 -132q-28 -13 -37 -17 +t-30.5 -17t-29.5 -23.5t-16 -29t-8 -40.5q0 -50 31.5 -82t81.5 -32q20 0 38 9l352 160q30 14 48 41.5t18 60.5zM1112 1024l-650 248q-24 8 -46 8q-53 0 -90.5 -37.5t-37.5 -90.5q0 -40 22.5 -73t59.5 -47l526 -200v-64h-640q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5 +t90.5 -37.5h535l233 106v198q0 63 46 106l111 102h-69zM1073 0q82 0 155 19l339 85q43 11 70 45.5t27 78.5v668q0 53 -37.5 90.5t-90.5 37.5h-308l-136 -126q-36 -33 -36 -82v-296q0 -46 33 -77t79 -31t79 35t33 81v208h32v-208q0 -70 -57 -114q52 -8 86.5 -48.5t34.5 -93.5 +q0 -42 -23 -78t-61 -53l-310 -141h91z" /> + <glyph glyph-name="_563" unicode="" horiz-adv-x="2048" +d="M1151 1536q61 0 116 -28t91 -77l572 -781q118 -159 118 -359v-355q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v177l-286 143h-546q-80 0 -136 56t-56 136v32q0 119 84.5 203.5t203.5 84.5h420l42 128h-686q-100 0 -173.5 67.5t-81.5 166.5q-65 79 -65 182v32 +q0 80 56 136t136 56h959zM1920 -64v355q0 157 -93 284l-573 781q-39 52 -103 52h-959q-26 0 -45 -19t-19 -45q0 -32 1.5 -49.5t9.5 -40.5t25 -43q10 31 35.5 50t56.5 19h832v-32h-832q-26 0 -45 -19t-19 -45q0 -44 3 -58q8 -44 44 -73t81 -29h640h91q40 0 68 -28t28 -68 +q0 -15 -5 -30l-64 -192q-10 -29 -35 -47.5t-56 -18.5h-443q-66 0 -113 -47t-47 -113v-32q0 -26 19 -45t45 -19h561q16 0 29 -7l317 -158q24 -13 38.5 -36t14.5 -50v-197q0 -26 19 -45t45 -19h384q26 0 45 19t19 45z" /> + <glyph glyph-name="_564" unicode="" horiz-adv-x="2048" +d="M459 -256q-77 0 -137.5 47.5t-79.5 122.5l-101 401q-13 57 -13 108q0 45 -5 67l-116 477q-7 27 -7 57q0 93 62 161t155 78q17 85 82.5 139t152.5 54q83 0 148 -51.5t85 -132.5l83 -348l103 428q20 81 85 132.5t148 51.5q89 0 155.5 -57.5t80.5 -144.5q92 -10 152 -79 +t60 -162q0 -24 -7 -59l-123 -512q10 7 37.5 28.5t38.5 29.5t35 23t41 20.5t41.5 11t49.5 5.5q105 0 180 -74t75 -179q0 -62 -28.5 -118t-78.5 -94l-507 -380q-68 -51 -153 -51h-694zM1104 1408q-38 0 -68.5 -24t-39.5 -62l-164 -682h-127l-145 602q-9 38 -39.5 62t-68.5 24 +q-48 0 -80 -33t-32 -80q0 -15 3 -28l132 -547h-26l-99 408q-9 37 -40 62.5t-69 25.5q-47 0 -80 -33t-33 -79q0 -14 3 -26l116 -478q7 -28 9 -86t10 -88l100 -401q8 -32 34 -52.5t59 -20.5h694q42 0 76 26l507 379q56 43 56 110q0 52 -37.5 88.5t-89.5 36.5q-43 0 -77 -26 +l-307 -230v227q0 4 32 138t68 282t39 161q4 18 4 29q0 47 -32 81t-79 34q-39 0 -69.5 -24t-39.5 -62l-116 -482h-26l150 624q3 14 3 28q0 48 -31.5 82t-79.5 34z" /> + <glyph glyph-name="_565" unicode="" horiz-adv-x="1792" +d="M640 1408q-53 0 -90.5 -37.5t-37.5 -90.5v-512v-384l-151 202q-41 54 -107 54q-52 0 -89 -38t-37 -90q0 -43 26 -77l384 -512q38 -51 102 -51h718q22 0 39.5 13.5t22.5 34.5l92 368q24 96 24 194v217q0 41 -28 71t-68 30t-68 -28t-28 -68h-32v61q0 48 -32 81.5t-80 33.5 +q-46 0 -79 -33t-33 -79v-64h-32v90q0 55 -37 94.5t-91 39.5q-53 0 -90.5 -37.5t-37.5 -90.5v-96h-32v570q0 55 -37 94.5t-91 39.5zM640 1536q107 0 181.5 -77.5t74.5 -184.5v-220q22 2 32 2q99 0 173 -69q47 21 99 21q113 0 184 -87q27 7 56 7q94 0 159 -67.5t65 -161.5 +v-217q0 -116 -28 -225l-92 -368q-16 -64 -68 -104.5t-118 -40.5h-718q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 105 74.5 180.5t179.5 75.5q71 0 130 -35v547q0 106 75 181t181 75zM768 128v384h-32v-384h32zM1024 128v384h-32v-384h32zM1280 128v384h-32 +v-384h32z" /> + <glyph glyph-name="_566" unicode="" +d="M1288 889q60 0 107 -23q141 -63 141 -226v-177q0 -94 -23 -186l-85 -339q-21 -86 -90.5 -140t-157.5 -54h-668q-106 0 -181 75t-75 181v401l-239 628q-17 45 -17 91q0 106 75 181t181 75q80 0 145.5 -45.5t93.5 -119.5l17 -44v113q0 106 75 181t181 75t181 -75t75 -181 +v-261q27 5 48 5q69 0 127.5 -36.5t88.5 -98.5zM1072 896q-33 0 -60.5 -18t-41.5 -48l-74 -163l-71 -155h55q50 0 90 -31.5t50 -80.5l154 338q10 20 10 46q0 46 -33 79t-79 33zM1293 761q-22 0 -40.5 -8t-29 -16t-23.5 -29.5t-17 -30.5t-17 -37l-132 -290q-10 -20 -10 -46 +q0 -46 33 -79t79 -33q33 0 60.5 18t41.5 48l160 352q9 18 9 38q0 50 -32 81.5t-82 31.5zM128 1120q0 -22 8 -46l248 -650v-69l102 111q43 46 106 46h198l106 233v535q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-640h-64l-200 526q-14 37 -47 59.5t-73 22.5 +q-53 0 -90.5 -37.5t-37.5 -90.5zM1180 -128q44 0 78.5 27t45.5 70l85 339q19 73 19 155v91l-141 -310q-17 -38 -53 -61t-78 -23q-53 0 -93.5 34.5t-48.5 86.5q-44 -57 -114 -57h-208v32h208q46 0 81 33t35 79t-31 79t-77 33h-296q-49 0 -82 -36l-126 -136v-308 +q0 -53 37.5 -90.5t90.5 -37.5h668z" /> + <glyph glyph-name="_567" unicode="" horiz-adv-x="1973" +d="M857 992v-117q0 -13 -9.5 -22t-22.5 -9h-298v-812q0 -13 -9 -22.5t-22 -9.5h-135q-13 0 -22.5 9t-9.5 23v812h-297q-13 0 -22.5 9t-9.5 22v117q0 14 9 23t23 9h793q13 0 22.5 -9.5t9.5 -22.5zM1895 995l77 -961q1 -13 -8 -24q-10 -10 -23 -10h-134q-12 0 -21 8.5 +t-10 20.5l-46 588l-189 -425q-8 -19 -29 -19h-120q-20 0 -29 19l-188 427l-45 -590q-1 -12 -10 -20.5t-21 -8.5h-135q-13 0 -23 10q-9 10 -9 24l78 961q1 12 10 20.5t21 8.5h142q20 0 29 -19l220 -520q10 -24 20 -51q3 7 9.5 24.5t10.5 26.5l221 520q9 19 29 19h141 +q13 0 22 -8.5t10 -20.5z" /> + <glyph glyph-name="_568" unicode="" horiz-adv-x="1792" +d="M1042 833q0 88 -60 121q-33 18 -117 18h-123v-281h162q66 0 102 37t36 105zM1094 548l205 -373q8 -17 -1 -31q-8 -16 -27 -16h-152q-20 0 -28 17l-194 365h-155v-350q0 -14 -9 -23t-23 -9h-134q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h294q128 0 190 -24q85 -31 134 -109 +t49 -180q0 -92 -42.5 -165.5t-115.5 -109.5q6 -10 9 -16zM896 1376q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM1792 640 +q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_569" unicode="" horiz-adv-x="1792" +d="M605 303q153 0 257 104q14 18 3 36l-45 82q-6 13 -24 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78 +q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-148 0 -246 -96.5t-98 -240.5q0 -146 97 -241.5t247 -95.5zM1235 303q153 0 257 104q14 18 4 36l-45 82q-8 14 -25 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5 +t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-147 0 -245.5 -96.5t-98.5 -240.5q0 -146 97 -241.5t247 -95.5zM896 1376 +q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191 +t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71z" /> + <glyph glyph-name="f260" unicode="" horiz-adv-x="2048" +d="M736 736l384 -384l-384 -384l-672 672l672 672l168 -168l-96 -96l-72 72l-480 -480l480 -480l193 193l-289 287zM1312 1312l672 -672l-672 -672l-168 168l96 96l72 -72l480 480l-480 480l-193 -193l289 -287l-96 -96l-384 384z" /> + <glyph glyph-name="f261" unicode="" horiz-adv-x="1792" +d="M717 182l271 271l-279 279l-88 -88l192 -191l-96 -96l-279 279l279 279l40 -40l87 87l-127 128l-454 -454zM1075 190l454 454l-454 454l-271 -271l279 -279l88 88l-192 191l96 96l279 -279l-279 -279l-40 40l-87 -88zM1792 640q0 -182 -71 -348t-191 -286t-286 -191 +t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_572" unicode="" horiz-adv-x="2304" +d="M651 539q0 -39 -27.5 -66.5t-65.5 -27.5q-39 0 -66.5 27.5t-27.5 66.5q0 38 27.5 65.5t66.5 27.5q38 0 65.5 -27.5t27.5 -65.5zM1805 540q0 -39 -27.5 -66.5t-66.5 -27.5t-66.5 27.5t-27.5 66.5t27.5 66t66.5 27t66.5 -27t27.5 -66zM765 539q0 79 -56.5 136t-136.5 57 +t-136.5 -56.5t-56.5 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM1918 540q0 80 -56.5 136.5t-136.5 56.5q-79 0 -136 -56.5t-57 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM850 539q0 -116 -81.5 -197.5t-196.5 -81.5q-116 0 -197.5 82t-81.5 197 +t82 196.5t197 81.5t196.5 -81.5t81.5 -196.5zM2004 540q0 -115 -81.5 -196.5t-197.5 -81.5q-115 0 -196.5 81.5t-81.5 196.5t81.5 196.5t196.5 81.5q116 0 197.5 -81.5t81.5 -196.5zM1040 537q0 191 -135.5 326.5t-326.5 135.5q-125 0 -231 -62t-168 -168.5t-62 -231.5 +t62 -231.5t168 -168.5t231 -62q191 0 326.5 135.5t135.5 326.5zM1708 1110q-254 111 -556 111q-319 0 -573 -110q117 0 223 -45.5t182.5 -122.5t122 -183t45.5 -223q0 115 43.5 219.5t118 180.5t177.5 123t217 50zM2187 537q0 191 -135 326.5t-326 135.5t-326.5 -135.5 +t-135.5 -326.5t135.5 -326.5t326.5 -135.5t326 135.5t135 326.5zM1921 1103h383q-44 -51 -75 -114.5t-40 -114.5q110 -151 110 -337q0 -156 -77 -288t-209 -208.5t-287 -76.5q-133 0 -249 56t-196 155q-47 -56 -129 -179q-11 22 -53.5 82.5t-74.5 97.5 +q-80 -99 -196.5 -155.5t-249.5 -56.5q-155 0 -287 76.5t-209 208.5t-77 288q0 186 110 337q-9 51 -40 114.5t-75 114.5h365q149 100 355 156.5t432 56.5q224 0 421 -56t348 -157z" /> + <glyph glyph-name="f263" unicode="" horiz-adv-x="1280" +d="M640 629q-188 0 -321 133t-133 320q0 188 133 321t321 133t321 -133t133 -321q0 -187 -133 -320t-321 -133zM640 1306q-92 0 -157.5 -65.5t-65.5 -158.5q0 -92 65.5 -157.5t157.5 -65.5t157.5 65.5t65.5 157.5q0 93 -65.5 158.5t-157.5 65.5zM1163 574q13 -27 15 -49.5 +t-4.5 -40.5t-26.5 -38.5t-42.5 -37t-61.5 -41.5q-115 -73 -315 -94l73 -72l267 -267q30 -31 30 -74t-30 -73l-12 -13q-31 -30 -74 -30t-74 30q-67 68 -267 268l-267 -268q-31 -30 -74 -30t-73 30l-12 13q-31 30 -31 73t31 74l267 267l72 72q-203 21 -317 94 +q-39 25 -61.5 41.5t-42.5 37t-26.5 38.5t-4.5 40.5t15 49.5q10 20 28 35t42 22t56 -2t65 -35q5 -4 15 -11t43 -24.5t69 -30.5t92 -24t113 -11q91 0 174 25.5t120 50.5l38 25q33 26 65 35t56 2t42 -22t28 -35z" /> + <glyph glyph-name="_574" unicode="" +d="M927 956q0 -66 -46.5 -112.5t-112.5 -46.5t-112.5 46.5t-46.5 112.5t46.5 112.5t112.5 46.5t112.5 -46.5t46.5 -112.5zM1141 593q-10 20 -28 32t-47.5 9.5t-60.5 -27.5q-10 -8 -29 -20t-81 -32t-127 -20t-124 18t-86 36l-27 18q-31 25 -60.5 27.5t-47.5 -9.5t-28 -32 +q-22 -45 -2 -74.5t87 -73.5q83 -53 226 -67l-51 -52q-142 -142 -191 -190q-22 -22 -22 -52.5t22 -52.5l9 -9q22 -22 52.5 -22t52.5 22l191 191q114 -115 191 -191q22 -22 52.5 -22t52.5 22l9 9q22 22 22 52.5t-22 52.5l-191 190l-52 52q141 14 225 67q67 44 87 73.5t-2 74.5 +zM1092 956q0 134 -95 229t-229 95t-229 -95t-95 -229t95 -229t229 -95t229 95t95 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="_575" unicode="" horiz-adv-x="1720" +d="M1565 1408q65 0 110 -45.5t45 -110.5v-519q0 -176 -68 -336t-182.5 -275t-274 -182.5t-334.5 -67.5q-176 0 -335.5 67.5t-274.5 182.5t-183 275t-68 336v519q0 64 46 110t110 46h1409zM861 344q47 0 82 33l404 388q37 35 37 85q0 49 -34.5 83.5t-83.5 34.5q-47 0 -82 -33 +l-323 -310l-323 310q-35 33 -81 33q-49 0 -83.5 -34.5t-34.5 -83.5q0 -51 36 -85l405 -388q33 -33 81 -33z" /> + <glyph glyph-name="_576" unicode="" horiz-adv-x="2304" +d="M1494 -103l-295 695q-25 -49 -158.5 -305.5t-198.5 -389.5q-1 -1 -27.5 -0.5t-26.5 1.5q-82 193 -255.5 587t-259.5 596q-21 50 -66.5 107.5t-103.5 100.5t-102 43q0 5 -0.5 24t-0.5 27h583v-50q-39 -2 -79.5 -16t-66.5 -43t-10 -64q26 -59 216.5 -499t235.5 -540 +q31 61 140 266.5t131 247.5q-19 39 -126 281t-136 295q-38 69 -201 71v50l513 -1v-47q-60 -2 -93.5 -25t-12.5 -69q33 -70 87 -189.5t86 -187.5q110 214 173 363q24 55 -10 79.5t-129 26.5q1 7 1 25v24q64 0 170.5 0.5t180 1t92.5 0.5v-49q-62 -2 -119 -33t-90 -81 +l-213 -442q13 -33 127.5 -290t121.5 -274l441 1017q-14 38 -49.5 62.5t-65 31.5t-55.5 8v50l460 -4l1 -2l-1 -44q-139 -4 -201 -145q-526 -1216 -559 -1291h-49z" /> + <glyph glyph-name="_577" unicode="" horiz-adv-x="1792" +d="M949 643q0 -26 -16.5 -45t-41.5 -19q-26 0 -45 16.5t-19 41.5q0 26 17 45t42 19t44 -16.5t19 -41.5zM964 585l350 581q-9 -8 -67.5 -62.5t-125.5 -116.5t-136.5 -127t-117 -110.5t-50.5 -51.5l-349 -580q7 7 67 62t126 116.5t136 127t117 111t50 50.5zM1611 640 +q0 -201 -104 -371q-3 2 -17 11t-26.5 16.5t-16.5 7.5q-13 0 -13 -13q0 -10 59 -44q-74 -112 -184.5 -190.5t-241.5 -110.5l-16 67q-1 10 -15 10q-5 0 -8 -5.5t-2 -9.5l16 -68q-72 -15 -146 -15q-199 0 -372 105q1 2 13 20.5t21.5 33.5t9.5 19q0 13 -13 13q-6 0 -17 -14.5 +t-22.5 -34.5t-13.5 -23q-113 75 -192 187.5t-110 244.5l69 15q10 3 10 15q0 5 -5.5 8t-10.5 2l-68 -15q-14 72 -14 139q0 206 109 379q2 -1 18.5 -12t30 -19t17.5 -8q13 0 13 12q0 6 -12.5 15.5t-32.5 21.5l-20 12q77 112 189 189t244 107l15 -67q2 -10 15 -10q5 0 8 5.5 +t2 10.5l-15 66q71 13 134 13q204 0 379 -109q-39 -56 -39 -65q0 -13 12 -13q11 0 48 64q111 -75 187.5 -186t107.5 -241l-56 -12q-10 -2 -10 -16q0 -5 5.5 -8t9.5 -2l57 13q14 -72 14 -140zM1696 640q0 163 -63.5 311t-170.5 255t-255 170.5t-311 63.5t-311 -63.5 +t-255 -170.5t-170.5 -255t-63.5 -311t63.5 -311t170.5 -255t255 -170.5t311 -63.5t311 63.5t255 170.5t170.5 255t63.5 311zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191 +t191 -286t71 -348z" /> + <glyph glyph-name="_578" unicode="" horiz-adv-x="1792" +d="M893 1536q240 2 451 -120q232 -134 352 -372l-742 39q-160 9 -294 -74.5t-185 -229.5l-276 424q128 159 311 245.5t383 87.5zM146 1131l337 -663q72 -143 211 -217t293 -45l-230 -451q-212 33 -385 157.5t-272.5 316t-99.5 411.5q0 267 146 491zM1732 962 +q58 -150 59.5 -310.5t-48.5 -306t-153 -272t-246 -209.5q-230 -133 -498 -119l405 623q88 131 82.5 290.5t-106.5 277.5zM896 942q125 0 213.5 -88.5t88.5 -213.5t-88.5 -213.5t-213.5 -88.5t-213.5 88.5t-88.5 213.5t88.5 213.5t213.5 88.5z" /> + <glyph glyph-name="_579" unicode="" horiz-adv-x="1792" +d="M903 -256q-283 0 -504.5 150.5t-329.5 398.5q-58 131 -67 301t26 332.5t111 312t179 242.5l-11 -281q11 14 68 15.5t70 -15.5q42 81 160.5 138t234.5 59q-54 -45 -119.5 -148.5t-58.5 -163.5q25 -8 62.5 -13.5t63 -7.5t68 -4t50.5 -3q15 -5 9.5 -45.5t-30.5 -75.5 +q-5 -7 -16.5 -18.5t-56.5 -35.5t-101 -34l15 -189l-139 67q-18 -43 -7.5 -81.5t36 -66.5t65.5 -41.5t81 -6.5q51 9 98 34.5t83.5 45t73.5 17.5q61 -4 89.5 -33t19.5 -65q-1 -2 -2.5 -5.5t-8.5 -12.5t-18 -15.5t-31.5 -10.5t-46.5 -1q-60 -95 -144.5 -135.5t-209.5 -29.5 +q74 -61 162.5 -82.5t168.5 -6t154.5 52t128 87.5t80.5 104q43 91 39 192.5t-37.5 188.5t-78.5 125q87 -38 137 -79.5t77 -112.5q15 170 -57.5 343t-209.5 284q265 -77 412 -279.5t151 -517.5q2 -127 -40.5 -255t-123.5 -238t-189 -196t-247.5 -135.5t-288.5 -49.5z" /> + <glyph glyph-name="_580" unicode="" horiz-adv-x="1792" +d="M1493 1308q-165 110 -359 110q-155 0 -293 -73t-240 -200q-75 -93 -119.5 -218t-48.5 -266v-42q4 -141 48.5 -266t119.5 -218q102 -127 240 -200t293 -73q194 0 359 110q-121 -108 -274.5 -168t-322.5 -60q-29 0 -43 1q-175 8 -333 82t-272 193t-181 281t-67 339 +q0 182 71 348t191 286t286 191t348 71h3q168 -1 320.5 -60.5t273.5 -167.5zM1792 640q0 -192 -77 -362.5t-213 -296.5q-104 -63 -222 -63q-137 0 -255 84q154 56 253.5 233t99.5 405q0 227 -99 404t-253 234q119 83 254 83q119 0 226 -65q135 -125 210.5 -295t75.5 -361z +" /> + <glyph glyph-name="_581" unicode="" horiz-adv-x="1792" +d="M1792 599q0 -56 -7 -104h-1151q0 -146 109.5 -244.5t257.5 -98.5q99 0 185.5 46.5t136.5 130.5h423q-56 -159 -170.5 -281t-267.5 -188.5t-321 -66.5q-187 0 -356 83q-228 -116 -394 -116q-237 0 -237 263q0 115 45 275q17 60 109 229q199 360 475 606 +q-184 -79 -427 -354q63 274 283.5 449.5t501.5 175.5q30 0 45 -1q255 117 433 117q64 0 116 -13t94.5 -40.5t66.5 -76.5t24 -115q0 -116 -75 -286q101 -182 101 -390zM1722 1239q0 83 -53 132t-137 49q-108 0 -254 -70q121 -47 222.5 -131.5t170.5 -195.5q51 135 51 216z +M128 2q0 -86 48.5 -132.5t134.5 -46.5q115 0 266 83q-122 72 -213.5 183t-137.5 245q-98 -205 -98 -332zM632 715h728q-5 142 -113 237t-251 95q-144 0 -251.5 -95t-112.5 -237z" /> + <glyph glyph-name="_582" unicode="" horiz-adv-x="2048" +d="M1792 288v960q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1248v-960q0 -66 -47 -113t-113 -47h-736v-128h352q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23 +v64q0 14 9 23t23 9h352v128h-736q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" /> + <glyph glyph-name="_583" unicode="" horiz-adv-x="1792" +d="M138 1408h197q-70 -64 -126 -149q-36 -56 -59 -115t-30 -125.5t-8.5 -120t10.5 -132t21 -126t28 -136.5q4 -19 6 -28q51 -238 81 -329q57 -171 152 -275h-272q-48 0 -82 34t-34 82v1304q0 48 34 82t82 34zM1346 1408h308q48 0 82 -34t34 -82v-1304q0 -48 -34 -82t-82 -34 +h-178q212 210 196 565l-469 -101q-2 -45 -12 -82t-31 -72t-59.5 -59.5t-93.5 -36.5q-123 -26 -199 40q-32 27 -53 61t-51.5 129t-64.5 258q-35 163 -45.5 263t-5.5 139t23 77q20 41 62.5 73t102.5 45q45 12 83.5 6.5t67 -17t54 -35t43 -48t34.5 -56.5l468 100 +q-68 175 -180 287z" /> + <glyph glyph-name="_584" unicode="" +d="M1401 -11l-6 -6q-113 -113 -259 -175q-154 -64 -317 -64q-165 0 -317 64q-148 63 -259 175q-113 112 -175 258q-42 103 -54 189q-4 28 48 36q51 8 56 -20q1 -1 1 -4q18 -90 46 -159q50 -124 152 -226q98 -98 226 -152q132 -56 276 -56q143 0 276 56q128 55 225 152l6 6 +q10 10 25 6q12 -3 33 -22q36 -37 17 -58zM929 604l-66 -66l63 -63q21 -21 -7 -49q-17 -17 -32 -17q-10 0 -19 10l-62 61l-66 -66q-5 -5 -15 -5q-15 0 -31 16l-2 2q-18 15 -18 29q0 7 8 17l66 65l-66 66q-16 16 14 45q18 18 31 18q6 0 13 -5l65 -66l65 65q18 17 48 -13 +q27 -27 11 -44zM1400 547q0 -118 -46 -228q-45 -105 -126 -186q-80 -80 -187 -126t-228 -46t-228 46t-187 126q-82 82 -125 186q-15 33 -15 40h-1q-9 27 43 44q50 16 60 -12q37 -99 97 -167h1v339v2q3 136 102 232q105 103 253 103q147 0 251 -103t104 -249 +q0 -147 -104.5 -251t-250.5 -104q-58 0 -112 16q-28 11 -13 61q16 51 44 43l14 -3q14 -3 33 -6t30 -3q104 0 176 71.5t72 174.5q0 101 -72 171q-71 71 -175 71q-107 0 -178 -80q-64 -72 -64 -160v-413q110 -67 242 -67q96 0 185 36.5t156 103.5t103.5 155t36.5 183 +q0 198 -141 339q-140 140 -339 140q-200 0 -340 -140q-53 -53 -77 -87l-2 -2q-8 -11 -13 -15.5t-21.5 -9.5t-38.5 3q-21 5 -36.5 16.5t-15.5 26.5v680q0 15 10.5 26.5t27.5 11.5h877q30 0 30 -55t-30 -55h-811v-483h1q40 42 102 84t108 61q109 46 231 46q121 0 228 -46 +t187 -126q81 -81 126 -186q46 -112 46 -229zM1369 1128q9 -8 9 -18t-5.5 -18t-16.5 -21q-26 -26 -39 -26q-9 0 -16 7q-106 91 -207 133q-128 56 -276 56q-133 0 -262 -49q-27 -10 -45 37q-9 25 -8 38q3 16 16 20q130 57 299 57q164 0 316 -64q137 -58 235 -152z" /> + <glyph glyph-name="_585" unicode="" horiz-adv-x="1792" +d="M1551 60q15 6 26 3t11 -17.5t-15 -33.5q-13 -16 -44 -43.5t-95.5 -68t-141 -74t-188 -58t-229.5 -24.5q-119 0 -238 31t-209 76.5t-172.5 104t-132.5 105t-84 87.5q-8 9 -10 16.5t1 12t8 7t11.5 2t11.5 -4.5q192 -117 300 -166q389 -176 799 -90q190 40 391 135z +M1758 175q11 -16 2.5 -69.5t-28.5 -102.5q-34 -83 -85 -124q-17 -14 -26 -9t0 24q21 45 44.5 121.5t6.5 98.5q-5 7 -15.5 11.5t-27 6t-29.5 2.5t-35 0t-31.5 -2t-31 -3t-22.5 -2q-6 -1 -13 -1.5t-11 -1t-8.5 -1t-7 -0.5h-5.5h-4.5t-3 0.5t-2 1.5l-1.5 3q-6 16 47 40t103 30 +q46 7 108 1t76 -24zM1364 618q0 -31 13.5 -64t32 -58t37.5 -46t33 -32l13 -11l-227 -224q-40 37 -79 75.5t-58 58.5l-19 20q-11 11 -25 33q-38 -59 -97.5 -102.5t-127.5 -63.5t-140 -23t-137.5 21t-117.5 65.5t-83 113t-31 162.5q0 84 28 154t72 116.5t106.5 83t122.5 57 +t130 34.5t119.5 18.5t99.5 6.5v127q0 65 -21 97q-34 53 -121 53q-6 0 -16.5 -1t-40.5 -12t-56 -29.5t-56 -59.5t-48 -96l-294 27q0 60 22 119t67 113t108 95t151.5 65.5t190.5 24.5q100 0 181 -25t129.5 -61.5t81 -83t45 -86t12.5 -73.5v-589zM692 597q0 -86 70 -133 +q66 -44 139 -22q84 25 114 123q14 45 14 101v162q-59 -2 -111 -12t-106.5 -33.5t-87 -71t-32.5 -114.5z" /> + <glyph glyph-name="_586" unicode="" horiz-adv-x="1792" +d="M1536 1280q52 0 90 -38t38 -90v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128zM1152 1376v-288q0 -14 9 -23t23 -9 +h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 1376v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM1536 -128v1024h-1408v-1024h1408zM896 448h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224 +v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224z" /> + <glyph glyph-name="_587" unicode="" horiz-adv-x="1792" +d="M1152 416v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23 +t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47 +t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_588" unicode="" horiz-adv-x="1792" +d="M1111 151l-46 -46q-9 -9 -22 -9t-23 9l-188 189l-188 -189q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22t9 23l189 188l-189 188q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l188 -188l188 188q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23l-188 -188l188 -188q9 -10 9 -23t-9 -22z +M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 +q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_589" unicode="" horiz-adv-x="1792" +d="M1303 572l-512 -512q-10 -9 -23 -9t-23 9l-288 288q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l220 -220l444 444q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23 +t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47 +t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" /> + <glyph glyph-name="_590" unicode="" horiz-adv-x="1792" +d="M448 1536q26 0 45 -19t19 -45v-891l536 429q17 14 40 14q26 0 45 -19t19 -45v-379l536 429q17 14 40 14q26 0 45 -19t19 -45v-1152q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h384z" /> + <glyph glyph-name="_591" unicode="" horiz-adv-x="1024" +d="M512 448q66 0 128 15v-655q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v655q62 -15 128 -15zM512 1536q212 0 362 -150t150 -362t-150 -362t-362 -150t-362 150t-150 362t150 362t362 150zM512 1312q14 0 23 9t9 23t-9 23t-23 9q-146 0 -249 -103t-103 -249 +q0 -14 9 -23t23 -9t23 9t9 23q0 119 84.5 203.5t203.5 84.5z" /> + <glyph glyph-name="_592" unicode="" horiz-adv-x="1792" +d="M1745 1239q10 -10 10 -23t-10 -23l-141 -141q-28 -28 -68 -28h-1344q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h576v64q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-64h512q40 0 68 -28zM768 320h256v-512q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v512zM1600 768 +q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-1344q-40 0 -68 28l-141 141q-10 10 -10 23t10 23l141 141q28 28 68 28h512v192h256v-192h576z" /> + <glyph glyph-name="_593" unicode="" horiz-adv-x="2048" +d="M2020 1525q28 -20 28 -53v-1408q0 -20 -11 -36t-29 -23l-640 -256q-24 -11 -48 0l-616 246l-616 -246q-10 -5 -24 -5q-19 0 -36 11q-28 20 -28 53v1408q0 20 11 36t29 23l640 256q24 11 48 0l616 -246l616 246q32 13 60 -6zM736 1390v-1270l576 -230v1270zM128 1173 +v-1270l544 217v1270zM1920 107v1270l-544 -217v-1270z" /> + <glyph glyph-name="_594" unicode="" horiz-adv-x="1792" +d="M512 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472q0 20 17 28l480 256q7 4 15 4zM1760 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472 +q0 20 17 28l480 256q7 4 15 4zM640 1536q8 0 14 -3l512 -256q18 -10 18 -29v-1472q0 -13 -9.5 -22.5t-22.5 -9.5q-8 0 -14 3l-512 256q-18 10 -18 29v1472q0 13 9.5 22.5t22.5 9.5z" /> + <glyph glyph-name="_595" unicode="" horiz-adv-x="1792" +d="M640 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 640q0 53 -37.5 90.5t-90.5 37.5 +t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-110 0 -211 18q-173 -173 -435 -229q-52 -10 -86 -13q-12 -1 -22 6t-13 18q-4 15 20 37q5 5 23.5 21.5t25.5 23.5t23.5 25.5t24 31.5t20.5 37 +t20 48t14.5 57.5t12.5 72.5q-146 90 -229.5 216.5t-83.5 269.5q0 174 120 321.5t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" /> + <glyph glyph-name="_596" unicode="" horiz-adv-x="1792" +d="M640 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 -53 -37.5 -90.5t-90.5 -37.5 +t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5 +t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51 +t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 130 71 248.5t191 204.5t286 136.5t348 50.5t348 -50.5t286 -136.5t191 -204.5t71 -248.5z" /> + <glyph glyph-name="_597" unicode="" horiz-adv-x="1024" +d="M512 345l512 295v-591l-512 -296v592zM0 640v-591l512 296zM512 1527v-591l-512 -296v591zM512 936l512 295v-591z" /> + <glyph glyph-name="_598" unicode="" horiz-adv-x="1792" +d="M1709 1018q-10 -236 -332 -651q-333 -431 -562 -431q-142 0 -240 263q-44 160 -132 482q-72 262 -157 262q-18 0 -127 -76l-77 98q24 21 108 96.5t130 115.5q156 138 241 146q95 9 153 -55.5t81 -203.5q44 -287 66 -373q55 -249 120 -249q51 0 154 161q101 161 109 246 +q13 139 -109 139q-57 0 -121 -26q120 393 459 382q251 -8 236 -326z" /> + <glyph glyph-name="f27e" unicode="" +d="M0 1408h1536v-1536h-1536v1536zM1085 293l-221 631l221 297h-634l221 -297l-221 -631l317 -304z" /> + <glyph glyph-name="uniF280" unicode="" +d="M0 1408h1536v-1536h-1536v1536zM908 1088l-12 -33l75 -83l-31 -114l25 -25l107 57l107 -57l25 25l-31 114l75 83l-12 33h-95l-53 96h-32l-53 -96h-95zM641 925q32 0 44.5 -16t11.5 -63l174 21q0 55 -17.5 92.5t-50.5 56t-69 25.5t-85 7q-133 0 -199 -57.5t-66 -182.5v-72 +h-96v-128h76q20 0 20 -8v-382q0 -14 -5 -20t-18 -7l-73 -7v-88h448v86l-149 14q-6 1 -8.5 1.5t-3.5 2.5t-0.5 4t1 7t0.5 10v387h191l38 128h-231q-6 0 -2 6t4 9v80q0 27 1.5 40.5t7.5 28t19.5 20t36.5 5.5zM1248 96v86l-54 9q-7 1 -9.5 2.5t-2.5 3t1 7.5t1 12v520h-275 +l-23 -101l83 -22q23 -7 23 -27v-370q0 -14 -6 -18.5t-20 -6.5l-70 -9v-86h352z" /> + <glyph glyph-name="uniF281" unicode="" horiz-adv-x="1792" +d="M1792 690q0 -58 -29.5 -105.5t-79.5 -72.5q12 -46 12 -96q0 -155 -106.5 -287t-290.5 -208.5t-400 -76.5t-399.5 76.5t-290 208.5t-106.5 287q0 47 11 94q-51 25 -82 73.5t-31 106.5q0 82 58 140.5t141 58.5q85 0 145 -63q218 152 515 162l116 521q3 13 15 21t26 5 +l369 -81q18 37 54 59.5t79 22.5q62 0 106 -43.5t44 -105.5t-44 -106t-106 -44t-105.5 43.5t-43.5 105.5l-334 74l-104 -472q300 -9 519 -160q58 61 143 61q83 0 141 -58.5t58 -140.5zM418 491q0 -62 43.5 -106t105.5 -44t106 44t44 106t-44 105.5t-106 43.5q-61 0 -105 -44 +t-44 -105zM1228 136q11 11 11 26t-11 26q-10 10 -25 10t-26 -10q-41 -42 -121 -62t-160 -20t-160 20t-121 62q-11 10 -26 10t-25 -10q-11 -10 -11 -25.5t11 -26.5q43 -43 118.5 -68t122.5 -29.5t91 -4.5t91 4.5t122.5 29.5t118.5 68zM1225 341q62 0 105.5 44t43.5 106 +q0 61 -44 105t-105 44q-62 0 -106 -43.5t-44 -105.5t44 -106t106 -44z" /> + <glyph glyph-name="_602" unicode="" horiz-adv-x="1792" +d="M69 741h1q16 126 58.5 241.5t115 217t167.5 176t223.5 117.5t276.5 43q231 0 414 -105.5t294 -303.5q104 -187 104 -442v-188h-1125q1 -111 53.5 -192.5t136.5 -122.5t189.5 -57t213 -3t208 46.5t173.5 84.5v-377q-92 -55 -229.5 -92t-312.5 -38t-316 53 +q-189 73 -311.5 249t-124.5 372q-3 242 111 412t325 268q-48 -60 -78 -125.5t-46 -159.5h635q8 77 -8 140t-47 101.5t-70.5 66.5t-80.5 41t-75 20.5t-56 8.5l-22 1q-135 -5 -259.5 -44.5t-223.5 -104.5t-176 -140.5t-138 -163.5z" /> + <glyph glyph-name="_603" unicode="" horiz-adv-x="2304" +d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" /> + <glyph glyph-name="_604" unicode="" horiz-adv-x="1792" +d="M1584 246l-218 111q-74 -120 -196.5 -189t-263.5 -69q-147 0 -271 72t-196 196t-72 270q0 110 42.5 209.5t115 172t172 115t209.5 42.5q131 0 247.5 -60.5t192.5 -168.5l215 125q-110 169 -286.5 265t-378.5 96q-161 0 -308 -63t-253 -169t-169 -253t-63 -308t63 -308 +t169 -253t253 -169t308 -63q213 0 397.5 107t290.5 292zM1030 643l693 -352q-116 -253 -334.5 -400t-492.5 -147q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q260 0 470.5 -133.5t335.5 -366.5zM1543 640h-39v-160h-96v352h136q32 0 54.5 -20 +t28.5 -48t1 -56t-27.5 -48t-57.5 -20z" /> + <glyph glyph-name="uniF285" unicode="" horiz-adv-x="1792" +d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" /> + <glyph glyph-name="uniF286" unicode="" horiz-adv-x="1792" +d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96 +q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5 +q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96 +q16 0 16 -16z" /> + <glyph glyph-name="_607" unicode="" horiz-adv-x="2304" +d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96 +q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5 +t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" /> + <glyph glyph-name="_608" unicode="" horiz-adv-x="1792" +d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348 +t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_609" unicode="" horiz-adv-x="2304" +d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22 +q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5 +q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13 +q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" /> + <glyph glyph-name="_610" unicode="" +d="M1500 -13q0 -89 -63 -152.5t-153 -63.5t-153.5 63.5t-63.5 152.5q0 90 63.5 153.5t153.5 63.5t153 -63.5t63 -153.5zM1267 268q-115 -15 -192.5 -102.5t-77.5 -205.5q0 -74 33 -138q-146 -78 -379 -78q-109 0 -201 21t-153.5 54.5t-110.5 76.5t-76 85t-44.5 83 +t-23.5 66.5t-6 39.5q0 19 4.5 42.5t18.5 56t36.5 58t64 43.5t94.5 18t94 -17.5t63 -41t35.5 -53t17.5 -49t4 -33.5q0 -34 -23 -81q28 -27 82 -42t93 -17l40 -1q115 0 190 51t75 133q0 26 -9 48.5t-31.5 44.5t-49.5 41t-74 44t-93.5 47.5t-119.5 56.5q-28 13 -43 20 +q-116 55 -187 100t-122.5 102t-72 125.5t-20.5 162.5q0 78 20.5 150t66 137.5t112.5 114t166.5 77t221.5 28.5q120 0 220 -26t164.5 -67t109.5 -94t64 -105.5t19 -103.5q0 -46 -15 -82.5t-36.5 -58t-48.5 -36t-49 -19.5t-39 -5h-8h-32t-39 5t-44 14t-41 28t-37 46t-24 70.5 +t-10 97.5q-15 16 -59 25.5t-81 10.5l-37 1q-68 0 -117.5 -31t-70.5 -70t-21 -76q0 -24 5 -43t24 -46t53 -51t97 -53.5t150 -58.5q76 -25 138.5 -53.5t109 -55.5t83 -59t60.5 -59.5t41 -62.5t26.5 -62t14.5 -63.5t6 -62t1 -62.5z" /> + <glyph glyph-name="_611" unicode="" +d="M704 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1152 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103 +t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_612" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 +t73 -273t198 -198t273 -73zM864 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192z" /> + <glyph glyph-name="_613" unicode="" +d="M1088 352v576q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 +t103 -385.5z" /> + <glyph glyph-name="_614" unicode="" +d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273 +t73 -273t198 -198t273 -73zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h576q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-576z" /> + <glyph glyph-name="_615" unicode="" horiz-adv-x="1792" +d="M1757 128l35 -313q3 -28 -16 -50q-19 -21 -48 -21h-1664q-29 0 -48 21q-19 22 -16 50l35 313h1722zM1664 967l86 -775h-1708l86 775q3 24 21 40.5t43 16.5h256v-128q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v128h384v-128q0 -53 37.5 -90.5t90.5 -37.5 +t90.5 37.5t37.5 90.5v128h256q25 0 43 -16.5t21 -40.5zM1280 1152v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="_616" unicode="" horiz-adv-x="2048" +d="M1920 768q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5h-15l-115 -662q-8 -46 -44 -76t-82 -30h-1280q-46 0 -82 30t-44 76l-115 662h-15q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5h1792zM485 -32q26 2 43.5 22.5t15.5 46.5l-32 416q-2 26 -22.5 43.5 +t-46.5 15.5t-43.5 -22.5t-15.5 -46.5l32 -416q2 -25 20.5 -42t43.5 -17h5zM896 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1280 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1632 27l32 416 +q2 26 -15.5 46.5t-43.5 22.5t-46.5 -15.5t-22.5 -43.5l-32 -416q-2 -26 15.5 -46.5t43.5 -22.5h5q25 0 43.5 17t20.5 42zM476 1244l-93 -412h-132l101 441q19 88 89 143.5t160 55.5h167q0 26 19 45t45 19h384q26 0 45 -19t19 -45h167q90 0 160 -55.5t89 -143.5l101 -441 +h-132l-93 412q-11 44 -45.5 72t-79.5 28h-167q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45h-167q-45 0 -79.5 -28t-45.5 -72z" /> + <glyph glyph-name="_617" unicode="" horiz-adv-x="1792" +d="M991 512l64 256h-254l-64 -256h254zM1759 1016l-56 -224q-7 -24 -31 -24h-327l-64 -256h311q15 0 25 -12q10 -14 6 -28l-56 -224q-5 -24 -31 -24h-327l-81 -328q-7 -24 -31 -24h-224q-16 0 -26 12q-9 12 -6 28l78 312h-254l-81 -328q-7 -24 -31 -24h-225q-15 0 -25 12 +q-9 12 -6 28l78 312h-311q-15 0 -25 12q-9 12 -6 28l56 224q7 24 31 24h327l64 256h-311q-15 0 -25 12q-10 14 -6 28l56 224q5 24 31 24h327l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h254l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h311 +q15 0 25 -12q9 -12 6 -28z" /> + <glyph glyph-name="_618" unicode="" +d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5 +t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" /> + <glyph glyph-name="_619" unicode="" horiz-adv-x="1024" +d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" /> + <glyph glyph-name="_620" unicode="" +d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5 +t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 +t271.5 -112.5t112.5 -271.5z" /> + <glyph glyph-name="_621" unicode="" horiz-adv-x="1792" +d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" /> + <glyph glyph-name="_622" unicode="" horiz-adv-x="1792" +d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111 +q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" /> + <glyph glyph-name="_623" unicode="" +d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14 +t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" /> + <glyph glyph-name="_624" unicode="" horiz-adv-x="1792" +d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57 +q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285 +q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" /> + <glyph glyph-name="_625" unicode="" horiz-adv-x="1792" +d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42 +q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z +M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298 +t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="_626" unicode="" +d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300 +l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z +M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" /> + <glyph glyph-name="_627" unicode="" +d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5 +t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5 +t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5 +t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="_628" unicode="" horiz-adv-x="1408" +d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457 +q-67 -192 -92 -234q-15 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521 +q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661 +q3 -1 7 1t7 4l3 2q11 9 11 17z" /> + <glyph glyph-name="_629" unicode="" horiz-adv-x="2304" +d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10 +t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5 +t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5 +h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96 +t9.5 -70.5z" /> + <glyph glyph-name="uniF2A0" unicode="" horiz-adv-x="1408" +d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5 +q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127 +l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272 +t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249 +q-18 -19 -45 -19z" /> + <glyph glyph-name="uniF2A1" unicode="" horiz-adv-x="2176" +d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352 +q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864 +q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136 +t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56 +t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56 +t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136 +t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" /> + <glyph glyph-name="uniF2A2" unicode="" horiz-adv-x="1792" +d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z +M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72 +t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45 +t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4 +q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" /> + <glyph glyph-name="uniF2A3" unicode="" horiz-adv-x="2304" +d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55 +q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5 +q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101 +q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35 +q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5 +q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" /> + <glyph glyph-name="uniF2A4" unicode="" horiz-adv-x="1792" +d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19 +t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74 +t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233 +l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" /> + <glyph glyph-name="uniF2A5" unicode="" +d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2 +q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10 +q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5 +t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="uniF2A6" unicode="" horiz-adv-x="1535" +d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5 +l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5 +q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9 +q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" /> + <glyph glyph-name="uniF2A7" unicode="" horiz-adv-x="1664" +d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37 +t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38 +l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147q-2 -1 -5 -3.5t-4 -4.5q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148 +q-34 23 -76 23q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26 +l-12 224q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" /> + <glyph glyph-name="uniF2A8" unicode="" horiz-adv-x="1792" +d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5 +q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841 +q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5 +q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" /> + <glyph glyph-name="uniF2A9" unicode="" horiz-adv-x="1280" +d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5 +q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z +M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" /> + <glyph glyph-name="uniF2AA" unicode="" +d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z +M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5 +q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 42 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 +t84.5 -203.5z" /> + <glyph glyph-name="uniF2AB" unicode="" +d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114 +q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5 +t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 +t103 -385.5z" /> + <glyph glyph-name="uniF2AC" unicode="" horiz-adv-x="1664" +d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35 +q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5 +t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" /> + <glyph glyph-name="uniF2AD" unicode="" +d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115 +q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15 +t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 +q119 0 203.5 -84.5t84.5 -203.5z" /> + <glyph glyph-name="uniF2AE" unicode="" horiz-adv-x="2304" +d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7 +q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158 +q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" /> + <glyph glyph-name="uniF2B0" unicode="" +d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104 +q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108 +l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z +M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" /> + <glyph glyph-name="uniF2B1" unicode="" horiz-adv-x="1664" +d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5 +t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" /> + <glyph glyph-name="uniF2B2" unicode="" horiz-adv-x="1792" +d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5 +t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114 +q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50 +q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5 +t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46 +q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5 +q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177 +t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" /> + <glyph glyph-name="uniF2B3" unicode="" +d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110 +h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" /> + <glyph glyph-name="uniF2B4" unicode="" +d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5 +q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" /> + <glyph glyph-name="uniF2B5" unicode="" horiz-adv-x="2304" +d="M192 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32zM1665 442q-10 13 -38.5 50t-41.5 54t-38 49t-42.5 53t-40.5 47t-45 49l-125 -140q-83 -94 -208.5 -92t-205.5 98q-57 69 -56.5 158t58.5 157l177 206q-22 11 -51 16.5t-47.5 6t-56.5 -0.5t-49 -1q-92 0 -158 -66 +l-158 -158h-155v-544q5 0 21 0.5t22 0t19.5 -2t20.5 -4.5t17.5 -8.5t18.5 -13.5l297 -292q115 -111 227 -111q78 0 125 47q57 -20 112.5 8t72.5 85q74 -6 127 44q20 18 36 45.5t14 50.5q10 -10 43 -10q43 0 77 21t49.5 53t12 71.5t-30.5 73.5zM1824 384h96v512h-93l-157 180 +q-66 76 -169 76h-167q-89 0 -146 -67l-209 -243q-28 -33 -28 -75t27 -75q43 -51 110 -52t111 49l193 218q25 23 53.5 21.5t47 -27t8.5 -56.5q16 -19 56 -63t60 -68q29 -36 82.5 -105.5t64.5 -84.5q52 -66 60 -140zM2112 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32z +M2304 960v-640q0 -26 -19 -45t-45 -19h-434q-27 -65 -82 -106.5t-125 -51.5q-33 -48 -80.5 -81.5t-102.5 -45.5q-42 -53 -104.5 -81.5t-128.5 -24.5q-60 -34 -126 -39.5t-127.5 14t-117 53.5t-103.5 81l-287 282h-358q-26 0 -45 19t-19 45v672q0 26 19 45t45 19h421 +q14 14 47 48t47.5 48t44 40t50.5 37.5t51 25.5t62 19.5t68 5.5h117q99 0 181 -56q82 56 181 56h167q35 0 67 -6t56.5 -14.5t51.5 -26.5t44.5 -31t43 -39.5t39 -42t41 -48t41.5 -48.5h355q26 0 45 -19t19 -45z" /> + <glyph glyph-name="uniF2B6" unicode="" horiz-adv-x="1792" +d="M1792 882v-978q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v978q0 15 11 24q8 7 39 34.5t41.5 36t45.5 37.5t70 55.5t96 73t143.5 107t192.5 140.5q5 4 52.5 40t71.5 52.5t64 35t69 18.5t69 -18.5t65 -35.5t71 -52t52 -40q110 -80 192.5 -140.5t143.5 -107 +t96 -73t70 -55.5t45.5 -37.5t41.5 -36t39 -34.5q11 -9 11 -24zM1228 297q263 191 345 252q11 8 12.5 20.5t-6.5 23.5l-38 52q-8 11 -21 12.5t-24 -6.5q-231 -169 -343 -250q-5 -3 -52 -39t-71.5 -52.5t-64.5 -35t-69 -18.5t-69 18.5t-64.5 35t-71.5 52.5t-52 39 +q-186 134 -343 250q-11 8 -24 6.5t-21 -12.5l-38 -52q-8 -11 -6.5 -23.5t12.5 -20.5q82 -61 345 -252q10 -8 50 -38t65 -47t64 -39.5t77.5 -33.5t75.5 -11t75.5 11t79 34.5t64.5 39.5t65 47.5t48 36.5z" /> + <glyph glyph-name="uniF2B7" unicode="" horiz-adv-x="1792" +d="M1474 623l39 -51q8 -11 6.5 -23.5t-11.5 -20.5q-43 -34 -126.5 -98.5t-146.5 -113t-67 -51.5q-39 -32 -60 -48t-60.5 -41t-76.5 -36.5t-74 -11.5h-1h-1q-37 0 -74 11.5t-76 36.5t-61 41.5t-60 47.5q-5 4 -65 50.5t-143.5 111t-122.5 94.5q-11 8 -12.5 20.5t6.5 23.5 +l37 52q8 11 21.5 13t24.5 -7q94 -73 306 -236q5 -4 43.5 -35t60.5 -46.5t56.5 -32.5t58.5 -17h1h1q24 0 58.5 17t56.5 32.5t60.5 46.5t43.5 35q258 198 313 242q11 8 24 6.5t21 -12.5zM1664 -96v928q-90 83 -159 139q-91 74 -389 304q-3 2 -43 35t-61 48t-56 32.5t-59 17.5 +h-1h-1q-24 0 -59 -17.5t-56 -32.5t-61 -48t-43 -35q-215 -166 -315.5 -245.5t-129.5 -104t-82 -74.5q-14 -12 -21 -19v-928q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 832v-928q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v928q0 56 41 94 +q123 114 350 290.5t233 181.5q36 30 59 47.5t61.5 42t76 36.5t74.5 12h1h1q37 0 74.5 -12t76 -36.5t61.5 -42t59 -47.5q43 -36 156 -122t226 -177t201 -173q41 -38 41 -94z" /> + <glyph glyph-name="uniF2B8" unicode="" +d="M330 1l202 -214l-34 236l-216 213zM556 -225l274 218l-11 245l-300 -215zM245 413l227 -213l-48 327l-245 204zM495 189l317 214l-14 324l-352 -200zM843 178l95 -80l-2 239l-103 79q0 -1 1 -8.5t0 -12t-5 -7.5l-78 -52l85 -70q7 -6 7 -88zM138 930l256 -200l-68 465 +l-279 173zM1173 267l15 234l-230 -164l2 -240zM417 722l373 194l-19 441l-423 -163zM1270 357l20 233l-226 142l-2 -105l144 -95q6 -4 4 -9l-7 -119zM1461 496l30 222l-179 -128l-20 -228zM1273 329l-71 49l-8 -117q0 -5 -4 -8l-234 -187q-7 -5 -14 0l-98 83l7 -161 +q0 -5 -4 -8l-293 -234q-4 -2 -6 -2q-8 2 -8 3l-228 242q-4 4 -59 277q-2 7 5 11l61 37q-94 86 -95 92l-72 351q-2 7 6 12l94 45q-133 100 -135 108l-96 466q-2 10 7 13l433 135q5 0 8 -1l317 -153q6 -4 6 -9l20 -463q0 -7 -6 -10l-118 -61l126 -85q5 -2 5 -8l5 -123l121 74 +q5 4 11 0l84 -56l3 110q0 6 5 9l206 126q6 3 11 0l245 -135q4 -4 5 -7t-6.5 -60t-17.5 -124.5t-10 -70.5q0 -5 -4 -7l-191 -153q-6 -5 -13 0z" /> + <glyph glyph-name="uniF2B9" unicode="" horiz-adv-x="1664" +d="M1201 298q0 57 -5.5 107t-21 100.5t-39.5 86t-64 58t-91 22.5q-6 -4 -33.5 -20.5t-42.5 -24.5t-40.5 -20t-49 -17t-46.5 -5t-46.5 5t-49 17t-40.5 20t-42.5 24.5t-33.5 20.5q-51 0 -91 -22.5t-64 -58t-39.5 -86t-21 -100.5t-5.5 -107q0 -73 42 -121.5t103 -48.5h576 +q61 0 103 48.5t42 121.5zM1028 892q0 108 -76.5 184t-183.5 76t-183.5 -76t-76.5 -184q0 -107 76.5 -183t183.5 -76t183.5 76t76.5 183zM1664 352v-192q0 -14 -9 -23t-23 -9h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216 +q66 0 113 -47t47 -113v-224h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23z" /> + <glyph glyph-name="uniF2BA" unicode="" horiz-adv-x="1664" +d="M1028 892q0 -107 -76.5 -183t-183.5 -76t-183.5 76t-76.5 183q0 108 76.5 184t183.5 76t183.5 -76t76.5 -184zM980 672q46 0 82.5 -17t60 -47.5t39.5 -67t24 -81t11.5 -82.5t3.5 -79q0 -67 -39.5 -118.5t-105.5 -51.5h-576q-66 0 -105.5 51.5t-39.5 118.5q0 48 4.5 93.5 +t18.5 98.5t36.5 91.5t63 64.5t93.5 26h5q7 -4 32 -19.5t35.5 -21t33 -17t37 -16t35 -9t39.5 -4.5t39.5 4.5t35 9t37 16t33 17t35.5 21t32 19.5zM1664 928q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96 +q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216q66 0 113 -47t47 -113v-224h96q13 0 22.5 -9.5t9.5 -22.5v-192zM1408 -96v1472q0 13 -9.5 22.5t-22.5 9.5h-1216 +q-13 0 -22.5 -9.5t-9.5 -22.5v-1472q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5z" /> + <glyph glyph-name="uniF2BB" unicode="" horiz-adv-x="2048" +d="M1024 405q0 64 -9 117.5t-29.5 103t-60.5 78t-97 28.5q-6 -4 -30 -18t-37.5 -21.5t-35.5 -17.5t-43 -14.5t-42 -4.5t-42 4.5t-43 14.5t-35.5 17.5t-37.5 21.5t-30 18q-57 0 -97 -28.5t-60.5 -78t-29.5 -103t-9 -117.5t37 -106.5t91 -42.5h512q54 0 91 42.5t37 106.5z +M867 925q0 94 -66.5 160.5t-160.5 66.5t-160.5 -66.5t-66.5 -160.5t66.5 -160.5t160.5 -66.5t160.5 66.5t66.5 160.5zM1792 416v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1792 676v56q0 15 -10.5 25.5t-25.5 10.5h-568 +q-15 0 -25.5 -10.5t-10.5 -25.5v-56q0 -15 10.5 -25.5t25.5 -10.5h568q15 0 25.5 10.5t10.5 25.5zM1792 928v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-352v96q0 14 -9 23t-23 9 +h-64q-14 0 -23 -9t-9 -23v-96h-768v96q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-96h-352q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2BC" unicode="" horiz-adv-x="2048" +d="M1024 405q0 -64 -37 -106.5t-91 -42.5h-512q-54 0 -91 42.5t-37 106.5t9 117.5t29.5 103t60.5 78t97 28.5q6 -4 30 -18t37.5 -21.5t35.5 -17.5t43 -14.5t42 -4.5t42 4.5t43 14.5t35.5 17.5t37.5 21.5t30 18q57 0 97 -28.5t60.5 -78t29.5 -103t9 -117.5zM867 925 +q0 -94 -66.5 -160.5t-160.5 -66.5t-160.5 66.5t-66.5 160.5t66.5 160.5t160.5 66.5t160.5 -66.5t66.5 -160.5zM1792 480v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1792 732v-56q0 -15 -10.5 -25.5t-25.5 -10.5h-568 +q-15 0 -25.5 10.5t-10.5 25.5v56q0 15 10.5 25.5t25.5 10.5h568q15 0 25.5 -10.5t10.5 -25.5zM1792 992v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1920 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1728q-13 0 -22.5 -9.5 +t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h352v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h768v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h352q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113 +t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2BD" unicode="" horiz-adv-x="1792" +d="M1523 197q-22 155 -87.5 257.5t-184.5 118.5q-67 -74 -159.5 -115.5t-195.5 -41.5t-195.5 41.5t-159.5 115.5q-119 -16 -184.5 -118.5t-87.5 -257.5q106 -150 271 -237.5t356 -87.5t356 87.5t271 237.5zM1280 896q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5 +t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1792 640q0 -182 -71 -347.5t-190.5 -286t-285.5 -191.5t-349 -71q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2BE" unicode="" horiz-adv-x="1792" +d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348q0 -181 -70.5 -347t-190.5 -286t-286 -191.5t-349 -71.5t-349 71t-285.5 191.5t-190.5 286t-71 347.5t71 348t191 286t286 191t348 71zM1515 185q149 205 149 455q0 156 -61 298t-164 245t-245 164t-298 61t-298 -61 +t-245 -164t-164 -245t-61 -298q0 -250 149 -455q66 327 306 327q131 -128 313 -128t313 128q240 0 306 -327zM1280 832q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5z" /> + <glyph glyph-name="uniF2C0" unicode="" +d="M1201 752q47 -14 89.5 -38t89 -73t79.5 -115.5t55 -172t22 -236.5q0 -154 -100 -263.5t-241 -109.5h-854q-141 0 -241 109.5t-100 263.5q0 131 22 236.5t55 172t79.5 115.5t89 73t89.5 38q-79 125 -79 272q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5 +t198.5 -40.5t163.5 -109.5t109.5 -163.5t40.5 -198.5q0 -147 -79 -272zM768 1408q-159 0 -271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5zM1195 -128q88 0 150.5 71.5t62.5 173.5q0 239 -78.5 377t-225.5 145 +q-145 -127 -336 -127t-336 127q-147 -7 -225.5 -145t-78.5 -377q0 -102 62.5 -173.5t150.5 -71.5h854z" /> + <glyph glyph-name="uniF2C1" unicode="" horiz-adv-x="1280" +d="M1024 278q0 -64 -37 -107t-91 -43h-512q-54 0 -91 43t-37 107t9 118t29.5 104t61 78.5t96.5 28.5q80 -75 188 -75t188 75q56 0 96.5 -28.5t61 -78.5t29.5 -104t9 -118zM870 797q0 -94 -67.5 -160.5t-162.5 -66.5t-162.5 66.5t-67.5 160.5t67.5 160.5t162.5 66.5 +t162.5 -66.5t67.5 -160.5zM1152 -96v1376h-1024v-1376q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1280 1376v-1472q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h352v-96q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v96h352 +q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2C2" unicode="" horiz-adv-x="2048" +d="M896 324q0 54 -7.5 100.5t-24.5 90t-51 68.5t-81 25q-64 -64 -156 -64t-156 64q-47 0 -81 -25t-51 -68.5t-24.5 -90t-7.5 -100.5q0 -55 31.5 -93.5t75.5 -38.5h426q44 0 75.5 38.5t31.5 93.5zM768 768q0 80 -56 136t-136 56t-136 -56t-56 -136t56 -136t136 -56t136 56 +t56 136zM1792 288v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1408 544v64q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1792 544v64q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23 +v-64q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1792 800v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM128 1152h1792v96q0 14 -9 23t-23 9h-1728q-14 0 -23 -9t-9 -23v-96zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728 +q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2C3" unicode="" horiz-adv-x="2048" +d="M896 324q0 -55 -31.5 -93.5t-75.5 -38.5h-426q-44 0 -75.5 38.5t-31.5 93.5q0 54 7.5 100.5t24.5 90t51 68.5t81 25q64 -64 156 -64t156 64q47 0 81 -25t51 -68.5t24.5 -90t7.5 -100.5zM768 768q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z +M1792 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1408 608v-64q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h320q14 0 23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v64 +q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 864v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1920 32v1120h-1792v-1120q0 -13 9.5 -22.5t22.5 -9.5h1728q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47 +h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2C4" unicode="" horiz-adv-x="1792" +d="M1255 749q0 318 -105 474.5t-330 156.5q-222 0 -326 -157t-104 -474q0 -316 104 -471.5t326 -155.5q74 0 131 17q-22 43 -39 73t-44 65t-53.5 56.5t-63 36t-77.5 14.5q-46 0 -79 -16l-49 97q105 91 276 91q132 0 215.5 -54t150.5 -155q67 149 67 402zM1645 117h117 +q3 -27 -2 -67t-26.5 -95t-58 -100.5t-107 -78t-162.5 -32.5q-71 0 -130.5 19t-105.5 56t-79 78t-66 96q-97 -27 -205 -27q-150 0 -292.5 58t-253 158.5t-178 249t-67.5 317.5q0 170 67.5 319.5t178.5 250.5t253.5 159t291.5 58q121 0 238.5 -36t217 -106t176 -164.5 +t119.5 -219t43 -261.5q0 -190 -80.5 -347.5t-218.5 -264.5q47 -70 93.5 -106.5t104.5 -36.5q61 0 94 37.5t38 85.5z" /> + <glyph glyph-name="uniF2C5" unicode="" horiz-adv-x="2304" +d="M453 -101q0 -21 -16 -37.5t-37 -16.5q-1 0 -13 3q-63 15 -162 140q-225 284 -225 676q0 341 213 614q39 51 95 103.5t94 52.5q19 0 35 -13.5t16 -32.5q0 -27 -63 -90q-98 -102 -147 -184q-119 -199 -119 -449q0 -281 123 -491q50 -85 136 -173q2 -3 14.5 -16t19.5 -21 +t17 -20.5t14.5 -23.5t4.5 -21zM1796 33q0 -29 -17.5 -48.5t-46.5 -19.5h-1081q-26 0 -45 19t-19 45q0 29 17.5 48.5t46.5 19.5h1081q26 0 45 -19t19 -45zM1581 644q0 -134 -67 -233q-25 -38 -69.5 -78.5t-83.5 -60.5q-16 -10 -27 -10q-7 0 -15 6t-8 12q0 9 19 30t42 46 +t42 67.5t19 88.5q0 76 -35 130q-29 42 -46 42q-3 0 -3 -5q0 -12 7.5 -35.5t7.5 -36.5q0 -22 -21.5 -35t-44.5 -13q-66 0 -66 76q0 15 1.5 44t1.5 44q0 25 -10 46q-13 25 -42 53.5t-51 28.5q-5 0 -7 -0.5t-3.5 -2.5t-1.5 -6q0 -2 16 -26t16 -54q0 -37 -19 -68t-46 -54 +t-53.5 -46t-45.5 -54t-19 -68q0 -98 42 -160q29 -43 79 -63q16 -5 17 -10q1 -2 1 -5q0 -16 -18 -16q-6 0 -33 11q-119 43 -195 139.5t-76 218.5q0 55 24.5 115.5t60 115t70.5 108.5t59.5 113.5t24.5 111.5q0 53 -25 94q-29 48 -56 64q-19 9 -19 21q0 20 41 20q50 0 110 -29 +q41 -19 71 -44.5t49.5 -51t33.5 -62.5t22 -69t16 -80q0 -1 3 -17.5t4.5 -25t5.5 -25t9 -27t11 -21.5t14.5 -16.5t18.5 -5.5q23 0 37 14t14 37q0 25 -20 67t-20 52t10 10q27 0 93 -70q72 -76 102.5 -156t30.5 -186zM2304 615q0 -274 -138 -503q-19 -32 -48 -72t-68 -86.5 +t-81 -77t-74 -30.5q-16 0 -31 15.5t-15 31.5q0 15 29 50.5t68.5 77t48.5 52.5q183 230 183 531q0 131 -20.5 235t-72.5 211q-58 119 -163 228q-2 3 -13 13.5t-16.5 16.5t-15 17.5t-15 20t-9.5 18.5t-4 19q0 19 16 35.5t35 16.5q70 0 196 -169q98 -131 146 -273t60 -314 +q2 -42 2 -64z" /> + <glyph glyph-name="uniF2C6" unicode="" horiz-adv-x="1792" +d="M1189 229l147 693q9 44 -10.5 63t-51.5 7l-864 -333q-29 -11 -39.5 -25t-2.5 -26.5t32 -19.5l221 -69l513 323q21 14 32 6q7 -5 -4 -15l-415 -375v0v0l-16 -228q23 0 45 22l108 104l224 -165q64 -36 81 38zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 +t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2C7" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v907h128v-907q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2C8" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v651h128v-651q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2C9" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v395h128v-395q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2CA" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v139h128v-139q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5 +t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192 +v128h192z" /> + <glyph glyph-name="uniF2CB" unicode="" horiz-adv-x="1024" +d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 79 56 135.5t136 56.5t136 -56.5t56 -135.5zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5z +M896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192v128h192z" /> + <glyph glyph-name="uniF2CC" unicode="" horiz-adv-x="1920" +d="M1433 1287q10 -10 10 -23t-10 -23l-626 -626q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l44 44q-72 91 -81.5 207t46.5 215q-74 71 -176 71q-106 0 -181 -75t-75 -181v-1280h-256v1280q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5q106 0 201 -41 +t166 -115q94 39 197 24.5t185 -79.5l44 44q10 10 23 10t23 -10zM1344 1024q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1600 896q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1856 1024q26 0 45 -19t19 -45t-19 -45t-45 -19 +t-45 19t-19 45t19 45t45 19zM1216 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1408 832q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM1728 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 768 +q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 640q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1600 768q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 512q-26 0 -45 19t-19 45t19 45t45 19t45 -19 +t19 -45t-19 -45t-45 -19zM1472 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 384 +q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 256q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19z" /> + <glyph glyph-name="uniF2CD" unicode="" horiz-adv-x="1792" +d="M1664 448v-192q0 -169 -128 -286v-194q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v118q-63 -22 -128 -22h-768q-65 0 -128 22v-110q0 -17 -9.5 -28.5t-22.5 -11.5h-64q-13 0 -22.5 11.5t-9.5 28.5v186q-128 117 -128 286v192h1536zM704 864q0 -14 -9 -23t-23 -9t-23 9 +t-9 23t9 23t23 9t23 -9t9 -23zM768 928q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM704 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1056q0 -14 -9 -23t-23 -9t-23 9 +t-9 23t9 23t23 9t23 -9t9 -23zM704 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v640q0 106 75 181t181 75q108 0 184 -78q46 19 98 12t93 -39l22 22q11 11 22 0l42 -42 +q11 -11 0 -22l-314 -314q-11 -11 -22 0l-42 42q-11 11 0 22l22 22q-36 46 -40.5 104t23.5 108q-37 35 -88 35q-53 0 -90.5 -37.5t-37.5 -90.5v-640h1504q14 0 23 -9t9 -23zM896 1056q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1120q0 -14 -9 -23t-23 -9 +t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM896 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1248q0 -14 -9 -23 +t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1024 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1088 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23z" /> + <glyph glyph-name="uniF2CE" unicode="" +d="M994 344q0 -86 -17 -197q-31 -215 -55 -313q-22 -90 -152 -90t-152 90q-24 98 -55 313q-17 110 -17 197q0 168 224 168t224 -168zM1536 768q0 -240 -134 -434t-350 -280q-8 -3 -15 3t-6 15q7 48 10 66q4 32 6 47q1 9 9 12q159 81 255.5 234t96.5 337q0 180 -91 330.5 +t-247 234.5t-337 74q-124 -7 -237 -61t-193.5 -140.5t-128 -202t-46.5 -240.5q1 -184 99 -336.5t257 -231.5q7 -3 9 -12q3 -21 6 -45q1 -9 5 -32.5t6 -35.5q1 -9 -6.5 -15t-15.5 -2q-148 58 -261 169.5t-173.5 264t-52.5 319.5q7 143 66 273.5t154.5 227t225 157.5t272.5 70 +q164 10 315.5 -46.5t261 -160.5t175 -250.5t65.5 -308.5zM994 800q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5zM1282 768q0 -122 -53.5 -228.5t-146.5 -177.5q-8 -6 -16 -2t-10 14q-6 52 -29 92q-7 10 3 20 +q58 54 91 127t33 155q0 111 -58.5 204t-157.5 141.5t-212 36.5q-133 -15 -229 -113t-109 -231q-10 -92 23.5 -176t98.5 -144q10 -10 3 -20q-24 -41 -29 -93q-2 -9 -10 -13t-16 2q-95 74 -148.5 183t-51.5 234q3 131 69 244t177 181.5t241 74.5q144 7 268 -60t196.5 -187.5 +t72.5 -263.5z" /> + <glyph glyph-name="uniF2D0" unicode="" horiz-adv-x="1792" +d="M256 128h1280v768h-1280v-768zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D1" unicode="" horiz-adv-x="1792" +d="M1792 224v-192q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D2" unicode="" horiz-adv-x="2048" +d="M256 0h768v512h-768v-512zM1280 512h512v768h-768v-256h96q66 0 113 -47t47 -113v-352zM2048 1376v-960q0 -66 -47 -113t-113 -47h-608v-352q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h608v352q0 66 47 113t113 47h960q66 0 113 -47 +t47 -113z" /> + <glyph glyph-name="uniF2D3" unicode="" horiz-adv-x="1792" +d="M1175 215l146 146q10 10 10 23t-10 23l-233 233l233 233q10 10 10 23t-10 23l-146 146q-10 10 -23 10t-23 -10l-233 -233l-233 233q-10 10 -23 10t-23 -10l-146 -146q-10 -10 -10 -23t10 -23l233 -233l-233 -233q-10 -10 -10 -23t10 -23l146 -146q10 -10 23 -10t23 10 +l233 233l233 -233q10 -10 23 -10t23 10zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D4" unicode="" horiz-adv-x="1792" +d="M1257 425l-146 -146q-10 -10 -23 -10t-23 10l-169 169l-169 -169q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l169 169l-169 169q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l169 -169l169 169q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 +l-169 -169l169 -169q10 -10 10 -23t-10 -23zM256 128h1280v1024h-1280v-1024zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D5" unicode="" horiz-adv-x="1792" +d="M1070 358l306 564h-654l-306 -564h654zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2D6" unicode="" horiz-adv-x="1794" +d="M1291 1060q-15 17 -35 8.5t-26 -28.5t5 -38q14 -17 40 -14.5t34 20.5t-18 52zM895 814q-8 -8 -19.5 -8t-18.5 8q-8 8 -8 19t8 18q7 8 18.5 8t19.5 -8q7 -7 7 -18t-7 -19zM1060 740l-35 -35q-12 -13 -29.5 -13t-30.5 13l-38 38q-12 13 -12 30t12 30l35 35q12 12 29.5 12 +t30.5 -12l38 -39q12 -12 12 -29.5t-12 -29.5zM951 870q-7 -8 -18.5 -8t-19.5 8q-7 8 -7 19t7 19q8 8 19 8t19 -8t8 -19t-8 -19zM1354 968q-34 -64 -107.5 -85.5t-127.5 16.5q-38 28 -61 66.5t-21 87.5t39 92t75.5 53t70.5 -5t70 -51q2 -2 13 -12.5t14.5 -13.5t13 -13.5 +t12.5 -15.5t10 -15.5t8.5 -18t4 -18.5t1 -21t-5 -22t-9.5 -24zM1555 486q3 20 -8.5 34.5t-27.5 21.5t-33 17t-23 20q-40 71 -84 98.5t-113 11.5q19 13 40 18.5t33 4.5l12 -1q2 45 -34 90q6 20 6.5 40.5t-2.5 30.5l-3 10q43 24 71 65t34 91q10 84 -43 150.5t-137 76.5 +q-60 7 -114 -18.5t-82 -74.5q-30 -51 -33.5 -101t14.5 -87t43.5 -64t56.5 -42q-45 4 -88 36t-57 88q-28 108 32 222q-16 21 -29 32q-50 0 -89 -19q19 24 42 37t36 14l13 1q0 50 -13 78q-10 21 -32.5 28.5t-47 -3.5t-37.5 -40q2 4 4 7q-7 -28 -6.5 -75.5t19 -117t48.5 -122.5 +q-25 -14 -47 -36q-35 -16 -85.5 -70.5t-84.5 -101.5l-33 -46q-90 -34 -181 -125.5t-75 -162.5q1 -16 11 -27q-15 -12 -30 -30q-21 -25 -21 -54t21.5 -40t63.5 6q41 19 77 49.5t55 60.5q-2 2 -6.5 5t-20.5 7.5t-33 3.5q23 5 51 12.5t40 10t27.5 6t26 4t23.5 0.5q14 -7 22 34 +q7 37 7 90q0 102 -40 150q106 -103 101 -219q-1 -29 -15 -50t-27 -27l-13 -6q-4 -7 -19 -32t-26 -45.5t-26.5 -52t-25 -61t-17 -63t-6.5 -66.5t10 -63q-35 54 -37 80q-22 -24 -34.5 -39t-33.5 -42t-30.5 -46t-16.5 -41t-0.5 -38t25.5 -27q45 -25 144 64t190.5 221.5 +t122.5 228.5q86 52 145 115.5t86 119.5q47 -93 154 -178q104 -83 167 -80q39 2 46 43zM1794 640q0 -182 -71 -348t-191 -286t-286.5 -191t-348.5 -71t-348.5 71t-286.5 191t-191 286t-71 348t71 348t191 286t286.5 191t348.5 71t348.5 -71t286.5 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2D7" unicode="" +d="M518 1353v-655q103 -1 191.5 1.5t125.5 5.5l37 3q68 2 90.5 24.5t39.5 94.5l33 142h103l-14 -322l7 -319h-103l-29 127q-15 68 -45 93t-84 26q-87 8 -352 8v-556q0 -78 43.5 -115.5t133.5 -37.5h357q35 0 59.5 2t55 7.5t54 18t48.5 32t46 50.5t39 73l93 216h89 +q-6 -37 -31.5 -252t-30.5 -276q-146 5 -263.5 8t-162.5 4h-44h-628l-376 -12v102l127 25q67 13 91.5 37t25.5 79l8 643q3 402 -8 645q-2 61 -25.5 84t-91.5 36l-127 24v102l376 -12h702q139 0 374 27q-6 -68 -14 -194.5t-12 -219.5l-5 -92h-93l-32 124q-31 121 -74 179.5 +t-113 58.5h-548q-28 0 -35.5 -8.5t-7.5 -30.5z" /> + <glyph glyph-name="uniF2D8" unicode="" +d="M922 739v-182q0 -4 0.5 -15t0 -15l-1.5 -12t-3.5 -11.5t-6.5 -7.5t-11 -5.5t-16 -1.5v309q9 0 16 -1t11 -5t6.5 -5.5t3.5 -9.5t1 -10.5v-13.5v-14zM1238 643v-121q0 -1 0.5 -12.5t0 -15.5t-2.5 -11.5t-7.5 -10.5t-13.5 -3q-9 0 -14 9q-4 10 -4 165v7v8.5v9t1.5 8.5l3.5 7 +t5 5.5t8 1.5q6 0 10 -1.5t6.5 -4.5t4 -6t2 -8.5t0.5 -8v-9.5v-9zM180 407h122v472h-122v-472zM614 407h106v472h-159l-28 -221q-20 148 -32 221h-158v-472h107v312l45 -312h76l43 319v-319zM1039 712q0 67 -5 90q-3 16 -11 28.5t-17 20.5t-25 14t-26.5 8.5t-31 4t-29 1.5 +h-29.5h-12h-91v-472h56q169 -1 197 24.5t25 180.5q-1 62 -1 100zM1356 515v133q0 29 -2 45t-9.5 33.5t-24.5 25t-46 7.5q-46 0 -77 -34v154h-117v-472h110l7 30q30 -36 77 -36q50 0 66 30.5t16 83.5zM1536 1248v-1216q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113 +v1216q0 66 47 113t113 47h1216q66 0 113 -47t47 -113z" /> + <glyph glyph-name="uniF2D9" unicode="" horiz-adv-x="2176" +d="M1143 -197q-6 1 -11 4q-13 8 -36 23t-86 65t-116.5 104.5t-112 140t-89.5 172.5q-17 3 -175 37q66 -213 235 -362t391 -184zM502 409l168 -28q-25 76 -41 167.5t-19 145.5l-4 53q-84 -82 -121 -224q5 -65 17 -114zM612 1018q-43 -64 -77 -148q44 46 74 68zM2049 584 +q0 161 -62 307t-167.5 252t-250.5 168.5t-304 62.5q-147 0 -281 -52.5t-240 -148.5q-30 -58 -45 -160q60 51 143 83.5t158.5 43t143 13.5t108.5 -1l40 -3q33 -1 53 -15.5t24.5 -33t6.5 -37t-1 -28.5q-126 11 -227.5 0.5t-183 -43.5t-142.5 -71.5t-131 -98.5 +q4 -36 11.5 -92.5t35.5 -178t62 -179.5q123 -6 247.5 14.5t214.5 53.5t162.5 67t109.5 59l37 24q22 16 39.5 20.5t30.5 -5t17 -34.5q14 -97 -39 -121q-208 -97 -467 -134q-135 -20 -317 -16q41 -96 110 -176.5t137 -127t130.5 -79t101.5 -43.5l39 -12q143 -23 263 15 +q195 99 314 289t119 418zM2123 621q-14 -135 -40 -212q-70 -208 -181.5 -346.5t-318.5 -253.5q-48 -33 -82 -44q-72 -26 -163 -16q-36 -3 -73 -3q-283 0 -504.5 173t-295.5 442q-1 0 -4 0.5t-5 0.5q-6 -50 2.5 -112.5t26 -115t36 -98t31.5 -71.5l14 -26q8 -12 54 -82 +q-71 38 -124.5 106.5t-78.5 140t-39.5 137t-17.5 107.5l-2 42q-5 2 -33.5 12.5t-48.5 18t-53 20.5t-57.5 25t-50 25.5t-42.5 27t-25 25.5q19 -10 50.5 -25.5t113 -45.5t145.5 -38l2 32q11 149 94 290q41 202 176 365q28 115 81 214q15 28 32 45t49 32q158 74 303.5 104 +t302 11t306.5 -97q220 -115 333 -336t87 -474z" /> + <glyph glyph-name="uniF2DA" unicode="" horiz-adv-x="1792" +d="M1341 752q29 44 -6.5 129.5t-121.5 142.5q-58 39 -125.5 53.5t-118 4.5t-68.5 -37q-12 -23 -4.5 -28t42.5 -10q23 -3 38.5 -5t44.5 -9.5t56 -17.5q36 -13 67.5 -31.5t53 -37t40 -38.5t30.5 -38t22 -34.5t16.5 -28.5t12 -18.5t10.5 -6t11 9.5zM1704 178 +q-52 -127 -148.5 -220t-214.5 -141.5t-253 -60.5t-266 13.5t-251 91t-210 161.5t-141.5 235.5t-46.5 303.5q1 41 8.5 84.5t12.5 64t24 80.5t23 73q-51 -208 1 -397t173 -318t291 -206t346 -83t349 74.5t289 244.5q20 27 18 14q0 -4 -4 -14zM1465 627q0 -104 -40.5 -199 +t-108.5 -164t-162 -109.5t-198 -40.5t-198 40.5t-162 109.5t-108.5 164t-40.5 199t40.5 199t108.5 164t162 109.5t198 40.5t198 -40.5t162 -109.5t108.5 -164t40.5 -199zM1752 915q-65 147 -180.5 251t-253 153.5t-292 53.5t-301 -36.5t-275.5 -129t-220 -211.5t-131 -297 +t-10 -373q-49 161 -51.5 311.5t35.5 272.5t109 227t165.5 180.5t207 126t232 71t242.5 9t236 -54t216 -124.5t178 -197q33 -50 62 -121t31 -112zM1690 573q12 244 -136.5 416t-396.5 240q-8 0 -10 5t24 8q125 -4 230 -50t173 -120t116 -168.5t58.5 -199t-1 -208 +t-61.5 -197.5t-122.5 -167t-185 -117.5t-248.5 -46.5q108 30 201.5 80t174 123t129.5 176.5t55 225.5z" /> + <glyph glyph-name="uniF2DB" unicode="" +d="M192 256v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 512v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 768v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16 +q0 16 16 16h112zM192 1024v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 1280v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM1280 1440v-1472q0 -40 -28 -68t-68 -28h-832q-40 0 -68 28 +t-28 68v1472q0 40 28 68t68 28h832q40 0 68 -28t28 -68zM1536 208v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 464v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 720v-32 +q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 976v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 1232v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16 +h48q16 0 16 -16z" /> + <glyph glyph-name="uniF2DC" unicode="" horiz-adv-x="1664" +d="M1566 419l-167 -33l186 -107q23 -13 29.5 -38.5t-6.5 -48.5q-14 -23 -39 -29.5t-48 6.5l-186 106l55 -160q13 -38 -12 -63.5t-60.5 -20.5t-48.5 42l-102 300l-271 156v-313l208 -238q16 -18 17 -39t-11 -36.5t-28.5 -25t-37 -5.5t-36.5 22l-112 128v-214q0 -26 -19 -45 +t-45 -19t-45 19t-19 45v214l-112 -128q-16 -18 -36.5 -22t-37 5.5t-28.5 25t-11 36.5t17 39l208 238v313l-271 -156l-102 -300q-13 -37 -48.5 -42t-60.5 20.5t-12 63.5l55 160l-186 -106q-23 -13 -48 -6.5t-39 29.5q-13 23 -6.5 48.5t29.5 38.5l186 107l-167 33 +q-29 6 -42 29t-8.5 46.5t25.5 40t50 10.5l310 -62l271 157l-271 157l-310 -62q-4 -1 -13 -1q-27 0 -44 18t-19 40t11 43t40 26l167 33l-186 107q-23 13 -29.5 38.5t6.5 48.5t39 30t48 -7l186 -106l-55 160q-13 38 12 63.5t60.5 20.5t48.5 -42l102 -300l271 -156v313 +l-208 238q-16 18 -17 39t11 36.5t28.5 25t37 5.5t36.5 -22l112 -128v214q0 26 19 45t45 19t45 -19t19 -45v-214l112 128q16 18 36.5 22t37 -5.5t28.5 -25t11 -36.5t-17 -39l-208 -238v-313l271 156l102 300q13 37 48.5 42t60.5 -20.5t12 -63.5l-55 -160l186 106 +q23 13 48 6.5t39 -29.5q13 -23 6.5 -48.5t-29.5 -38.5l-186 -107l167 -33q27 -5 40 -26t11 -43t-19 -40t-44 -18q-9 0 -13 1l-310 62l-271 -157l271 -157l310 62q29 6 50 -10.5t25.5 -40t-8.5 -46.5t-42 -29z" /> + <glyph glyph-name="uniF2DD" unicode="" horiz-adv-x="1792" +d="M1473 607q7 118 -33 226.5t-113 189t-177 131t-221 57.5q-116 7 -225.5 -32t-192 -110.5t-135 -175t-59.5 -220.5q-7 -118 33 -226.5t113 -189t177.5 -131t221.5 -57.5q155 -9 293 59t224 195.5t94 283.5zM1792 1536l-349 -348q120 -117 180.5 -272t50.5 -321 +q-11 -183 -102 -339t-241 -255.5t-332 -124.5l-999 -132l347 347q-120 116 -180.5 271.5t-50.5 321.5q11 184 102 340t241.5 255.5t332.5 124.5q167 22 500 66t500 66z" /> + <glyph glyph-name="uniF2DE" unicode="" horiz-adv-x="1792" +d="M948 508l163 -329h-51l-175 350l-171 -350h-49l179 374l-78 33l21 49l240 -102l-21 -50zM563 1100l304 -130l-130 -304l-304 130zM907 915l240 -103l-103 -239l-239 102zM1188 765l191 -81l-82 -190l-190 81zM1680 640q0 159 -62 304t-167.5 250.5t-250.5 167.5t-304 62 +t-304 -62t-250.5 -167.5t-167.5 -250.5t-62 -304t62 -304t167.5 -250.5t250.5 -167.5t304 -62t304 62t250.5 167.5t167.5 250.5t62 304zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71 +t286 -191t191 -286t71 -348z" /> + <glyph glyph-name="uniF2E0" unicode="" horiz-adv-x="1920" +d="M1334 302q-4 24 -27.5 34t-49.5 10.5t-48.5 12.5t-25.5 38q-5 47 33 139.5t75 181t32 127.5q-14 101 -117 103q-45 1 -75 -16l-3 -2l-5 -2.5t-4.5 -2t-5 -2t-5 -0.5t-6 1.5t-6 3.5t-6.5 5q-3 2 -9 8.5t-9 9t-8.5 7.5t-9.5 7.5t-9.5 5.5t-11 4.5t-11.5 2.5q-30 5 -48 -3 +t-45 -31q-1 -1 -9 -8.5t-12.5 -11t-15 -10t-16.5 -5.5t-17 3q-54 27 -84 40q-41 18 -94 -5t-76 -65q-16 -28 -41 -98.5t-43.5 -132.5t-40 -134t-21.5 -73q-22 -69 18.5 -119t110.5 -46q30 2 50.5 15t38.5 46q7 13 79 199.5t77 194.5q6 11 21.5 18t29.5 0q27 -15 21 -53 +q-2 -18 -51 -139.5t-50 -132.5q-6 -38 19.5 -56.5t60.5 -7t55 49.5q4 8 45.5 92t81.5 163.5t46 88.5q20 29 41 28q29 0 25 -38q-2 -16 -65.5 -147.5t-70.5 -159.5q-12 -53 13 -103t74 -74q17 -9 51 -15.5t71.5 -8t62.5 14t20 48.5zM383 86q3 -15 -5 -27.5t-23 -15.5 +q-14 -3 -26.5 5t-15.5 23q-3 14 5 27t22 16t27 -5t16 -23zM953 -177q12 -17 8.5 -37.5t-20.5 -32.5t-37.5 -8t-32.5 21q-11 17 -7.5 37.5t20.5 32.5t37.5 8t31.5 -21zM177 635q-18 -27 -49.5 -33t-57.5 13q-26 18 -32 50t12 58q18 27 49.5 33t57.5 -12q26 -19 32 -50.5 +t-12 -58.5zM1467 -42q19 -28 13 -61.5t-34 -52.5t-60.5 -13t-51.5 34t-13 61t33 53q28 19 60.5 13t52.5 -34zM1579 562q69 -113 42.5 -244.5t-134.5 -207.5q-90 -63 -199 -60q-20 -80 -84.5 -127t-143.5 -44.5t-140 57.5q-12 -9 -13 -10q-103 -71 -225 -48.5t-193 126.5 +q-50 73 -53 164q-83 14 -142.5 70.5t-80.5 128t-2 152t81 138.5q-36 60 -38 128t24.5 125t79.5 98.5t121 50.5q32 85 99 148t146.5 91.5t168 17t159.5 -66.5q72 21 140 17.5t128.5 -36t104.5 -80t67.5 -115t17.5 -140.5q52 -16 87 -57t45.5 -89t-5.5 -99.5t-58 -87.5z +M455 1222q14 -20 9.5 -44.5t-24.5 -38.5q-19 -14 -43.5 -9.5t-37.5 24.5q-14 20 -9.5 44.5t24.5 38.5q19 14 43.5 9.5t37.5 -24.5zM614 1503q4 -16 -5 -30.5t-26 -18.5t-31 5.5t-18 26.5q-3 17 6.5 31t25.5 18q17 4 31 -5.5t17 -26.5zM1800 555q4 -20 -6.5 -37t-30.5 -21 +q-19 -4 -36 6.5t-21 30.5t6.5 37t30.5 22q20 4 36.5 -7.5t20.5 -30.5zM1136 1448q16 -27 8.5 -58.5t-35.5 -47.5q-27 -16 -57.5 -8.5t-46.5 34.5q-16 28 -8.5 59t34.5 48t58 9t47 -36zM1882 792q4 -15 -4 -27.5t-23 -16.5q-15 -3 -27.5 5.5t-15.5 22.5q-3 15 5 28t23 16 +q14 3 26.5 -5t15.5 -23zM1691 1033q15 -22 10.5 -49t-26.5 -43q-22 -15 -49 -10t-42 27t-10 49t27 43t48.5 11t41.5 -28z" /> + <glyph glyph-name="uniF2E1" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E2" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E3" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E4" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E5" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E6" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E7" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="_698" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2E9" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EA" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EB" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EC" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2ED" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="uniF2EE" unicode="" horiz-adv-x="1792" + /> + <glyph glyph-name="lessequal" unicode="" horiz-adv-x="1792" + /> + </font> +</defs></svg> diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000000..35acda2fa11 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000000..400014a4b06 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000000..4d13fc60404 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000000..88ad05b9ff4 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000000..c4e3d804b57 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000000..c6dff51f063 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000000..bb195043cfc Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000000..76114bc0336 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000000..3404f37e2e3 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000000..ae1307ff5f4 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000000..3bf9843328a Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000000..0d9ae7e1a45 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/docs/_static/custom.css b/_static/custom.css similarity index 100% rename from docs/_static/custom.css rename to _static/custom.css diff --git a/_static/dark_mode_css/custom.css b/_static/dark_mode_css/custom.css new file mode 100644 index 00000000000..989c2ada1eb --- /dev/null +++ b/_static/dark_mode_css/custom.css @@ -0,0 +1,77 @@ +.wy-side-nav-search input[type='text'] { + border-radius: 3px; +} + +input[type='color'], +input[type='date'], +input[type='datetime-local'], +input[type='datetime'], +input[type='email'], +input[type='month'], +input[type='number'], +input[type='password'], +input[type='search'], +input[type='tel'], +input[type='text'], +input[type='time'], +input[type='url'], +input[type='week'] { + box-shadow: none; +} + +.theme-switcher { + border-radius: 50%; + position: fixed; + right: 1.6em; + bottom: 1.4em; + z-index: 3; + border: none; + height: 2.2em; + width: 2.2em; + background-color: #fcfcfc; + font-size: 20px; + -webkit-box-shadow: 0px 3px 14px 4px rgba(0, 0, 0, 0.62); + box-shadow: 0px 3px 14px 4px rgba(0, 0, 0, 0.62); + color: #404040; + transition: all 0.3s ease-in-out; +} + +.wy-nav-content a, +.wy-nav-content a:visited { + color: #3091d1; +} + +body, +.wy-nav-content-wrap, +.wy-nav-content, +.section, +.highlight, +.rst-content div[class^='highlight'], +.wy-nav-content a, +.btn-neutral, +.btn, +footer, +.wy-nav-side, +.wy-menu-vertical li, +.wy-menu-vertical a, +.wy-side-nav-search .wy-dropdown, +.wy-side-nav-search a, +.wy-side-nav-search input, +html.writer-html4 .rst-content dl:not(.docutils) > dt, +html.writer-html5 + .rst-content + dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) + > dt, +.rst-content code, +.rst-content tt, +html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt, +html.writer-html5 + .rst-content + dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) + dl:not(.field-list) + > dt, +code, +.rst-content code.xref, +.rst-content tt.xref { + transition: all 0.2s ease-in-out; +} diff --git a/_static/dark_mode_css/dark.css b/_static/dark_mode_css/dark.css new file mode 100644 index 00000000000..fb8802d7e71 --- /dev/null +++ b/_static/dark_mode_css/dark.css @@ -0,0 +1,501 @@ +:root { + --dark-text-color: #c1c1c1; + --dark-link-color: #249ee8; +} + +html[data-theme='dark'] body { + color: #bfbfbf; +} + +html[data-theme='dark'] .wy-nav-content-wrap { + background-color: #101010; +} + +html[data-theme='dark'] .wy-nav-content { + background-color: #141414; +} + +html[data-theme='dark'] .section { + color: var(--dark-text-color); +} + +html[data-theme='dark'] .highlight { + background-color: #17181c; +} + +html[data-theme='dark'] .highlight .nn { + color: var(--dark-text-color); +} + +html[data-theme='dark'] .highlight .nb { + color: #8bb8df; +} + +html[data-theme='dark'] .highlight .kn, +html[data-theme='dark'] .highlight .kc, +html[data-theme='dark'] .highlight .k { + color: #41c2ea; +} + +html[data-theme='dark'] .highlight .s1, +html[data-theme='dark'] .highlight .s2 { + color: #b3e87f; +} + +html[data-theme='dark'] .highlight .nt { + color: #ccb350; +} + +html[data-theme='dark'] .highlight .c1 { + color: #686868; +} + +html[data-theme='dark'] .rst-content div[class^='highlight'] { + border-color: #1a1a1a; +} + +html[data-theme='dark'] .wy-nav-content a, +html[data-theme='dark'] .wy-nav-content a:visited { + color: var(--dark-link-color); +} + +html[data-theme='dark'] .btn-neutral { + background-color: #17181c !important; +} + +html[data-theme='dark'] .btn-neutral:hover { + background-color: #101114 !important; +} + +html[data-theme='dark'] .btn-neutral:visited { + color: #c1c1c1 !important; +} + +html[data-theme='dark'] .btn { + box-shadow: none; +} + +html[data-theme='dark'] footer { + color: #bdbdbd; +} + +html[data-theme='dark'] .wy-nav-side { + background-color: #0d0d0d; +} + +html[data-theme='dark'] .wy-menu-vertical li.current { + background-color: #141414; +} + +html[data-theme='dark'] .wy-menu-vertical li.current > a, +html[data-theme='dark'] .wy-menu-vertical li.on a { + background-color: #141415; + color: var(--dark-text-color); +} + +html[data-theme='dark'] .wy-menu-vertical li.toctree-l1.current > a, +html[data-theme='dark'] .wy-menu-vertical li.current a { + border-color: #0b0c0d; +} + +html[data-theme='dark'] .wy-menu-vertical li.current a { + color: #bbb; +} + +html[data-theme='dark'] .wy-menu-vertical li.current a:hover { + background-color: #222; +} + +html[data-theme='dark'] .wy-menu-vertical a:hover, +html[data-theme='dark'] .wy-menu-vertical li.current > a:hover, +html[data-theme='dark'] .wy-menu-vertical li.on a:hover { + background-color: #1e1e1e; +} + +html[data-theme='dark'] .wy-menu-vertical li.toctree-l2.current > a, +html[data-theme='dark'] + .wy-menu-vertical + li.toctree-l2.current + li.toctree-l3 + > a { + background-color: #18181a; +} + +html[data-theme='dark'] .wy-side-nav-search { + background-color: #0b152d; +} + +html[data-theme='dark'] .wy-side-nav-search .wy-dropdown > a, +html[data-theme='dark'] .wy-side-nav-search > a { + color: #ddd; +} + +html[data-theme='dark'] .wy-side-nav-search input[type='text'] { + border-color: #111; + background-color: #141414; + color: var(--dark-text-color); +} + +html[data-theme='dark'] .theme-switcher { + background-color: #0b0c0d; + color: var(--dark-text-color); +} + +html[data-theme='dark'].writer-html4 .rst-content dl:not(.docutils) > dt, +html[data-theme='dark'].writer-html5 + .rst-content + dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) + > dt { + background-color: #0b0b0b; + color: #007dce; + border-color: #282828; +} + +html[data-theme='dark'] .rst-content code, +html[data-theme='dark'] .rst-content tt { + color: var(--dark-text-color); +} + +html[data-theme='dark'].writer-html4 + .rst-content + dl:not(.docutils) + dl:not(.field-list) + > dt, +html[data-theme='dark'].writer-html5 + .rst-content + dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) + dl:not(.field-list) + > dt { + background-color: #0f0f0f; + color: #959595; + border-color: #2b2b2b; +} + +html[data-theme='dark'] .rst-content code, +html[data-theme='dark'] .rst-content tt, +html[data-theme='dark'] code { + background-color: #2d2d2d; + border-color: #1c1c1c; +} + +html[data-theme='dark'] .rst-content code.xref, +html[data-theme='dark'] .rst-content tt.xref, +html[data-theme='dark'] a .rst-content code, +html[data-theme='dark'] a .rst-content tt { + color: #cecece; +} + +html[data-theme='dark'] .rst-content .hint, +html[data-theme='dark'] .rst-content .important, +html[data-theme='dark'] .rst-content .tip, +html[data-theme='dark'] .rst-content .wy-alert-success.admonition, +html[data-theme='dark'] .rst-content .wy-alert-success.admonition-todo, +html[data-theme='dark'] .rst-content .wy-alert-success.attention, +html[data-theme='dark'] .rst-content .wy-alert-success.caution, +html[data-theme='dark'] .rst-content .wy-alert-success.danger, +html[data-theme='dark'] .rst-content .wy-alert-success.error, +html[data-theme='dark'] .rst-content .wy-alert-success.note, +html[data-theme='dark'] .rst-content .wy-alert-success.seealso, +html[data-theme='dark'] .rst-content .wy-alert-success.warning, +html[data-theme='dark'] .wy-alert.wy-alert-success { + background-color: #00392e; +} + +html[data-theme='dark'] .rst-content .hint .admonition-title, +html[data-theme='dark'] .rst-content .hint .wy-alert-title, +html[data-theme='dark'] .rst-content .important .admonition-title, +html[data-theme='dark'] .rst-content .important .wy-alert-title, +html[data-theme='dark'] .rst-content .tip .admonition-title, +html[data-theme='dark'] .rst-content .tip .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.admonition-todo + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.admonition-todo + .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.admonition + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.admonition + .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.attention + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.attention + .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.caution + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-success.caution .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-success.danger .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-success.danger .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-success.error .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-success.error .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-success.note .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-success.note .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.seealso + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-success.seealso .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-success.warning + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-success.warning .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert.wy-alert-success + .admonition-title, +html[data-theme='dark'] + .wy-alert.wy-alert-success + .rst-content + .admonition-title, +html[data-theme='dark'] .wy-alert.wy-alert-success .wy-alert-title { + background-color: #006a56; +} + +html[data-theme='dark'] .rst-content .note, +html[data-theme='dark'] .rst-content .seealso, +html[data-theme='dark'] .rst-content .wy-alert-info.admonition, +html[data-theme='dark'] .rst-content .wy-alert-info.admonition-todo, +html[data-theme='dark'] .rst-content .wy-alert-info.attention, +html[data-theme='dark'] .rst-content .wy-alert-info.caution, +html[data-theme='dark'] .rst-content .wy-alert-info.danger, +html[data-theme='dark'] .rst-content .wy-alert-info.error, +html[data-theme='dark'] .rst-content .wy-alert-info.hint, +html[data-theme='dark'] .rst-content .wy-alert-info.important, +html[data-theme='dark'] .rst-content .wy-alert-info.tip, +html[data-theme='dark'] .rst-content .wy-alert-info.warning, +html[data-theme='dark'] .wy-alert.wy-alert-info { + background-color: #002c4d; +} + +html[data-theme='dark'] .rst-content .note .admonition-title, +html[data-theme='dark'] .rst-content .note .wy-alert-title, +html[data-theme='dark'] .rst-content .seealso .admonition-title, +html[data-theme='dark'] .rst-content .seealso .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-info.admonition-todo + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-info.admonition-todo + .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-info.admonition + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.admonition .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.attention .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.attention .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.caution .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.caution .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.danger .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.danger .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.error .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.error .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.hint .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.hint .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.important .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.important .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.tip .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.tip .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-info.warning .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-info.warning .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert.wy-alert-info .admonition-title, +html[data-theme='dark'] .wy-alert.wy-alert-info .rst-content .admonition-title, +html[data-theme='dark'] .wy-alert.wy-alert-info .wy-alert-title { + background-color: #004a7b; +} + +html[data-theme='dark'] .rst-content .admonition-todo, +html[data-theme='dark'] .rst-content .attention, +html[data-theme='dark'] .rst-content .caution, +html[data-theme='dark'] .rst-content .warning, +html[data-theme='dark'] .rst-content .wy-alert-warning.admonition, +html[data-theme='dark'] .rst-content .wy-alert-warning.danger, +html[data-theme='dark'] .rst-content .wy-alert-warning.error, +html[data-theme='dark'] .rst-content .wy-alert-warning.hint, +html[data-theme='dark'] .rst-content .wy-alert-warning.important, +html[data-theme='dark'] .rst-content .wy-alert-warning.note, +html[data-theme='dark'] .rst-content .wy-alert-warning.seealso, +html[data-theme='dark'] .rst-content .wy-alert-warning.tip, +html[data-theme='dark'] .wy-alert.wy-alert-warning { + background-color: #533500; +} + +html[data-theme='dark'] .rst-content .admonition-todo .admonition-title, +html[data-theme='dark'] .rst-content .admonition-todo .wy-alert-title, +html[data-theme='dark'] .rst-content .attention .admonition-title, +html[data-theme='dark'] .rst-content .attention .wy-alert-title, +html[data-theme='dark'] .rst-content .caution .admonition-title, +html[data-theme='dark'] .rst-content .caution .wy-alert-title, +html[data-theme='dark'] .rst-content .warning .admonition-title, +html[data-theme='dark'] .rst-content .warning .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-warning.admonition + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-warning.admonition + .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.danger .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.danger .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.error .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.error .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.hint .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.hint .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-warning.important + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-warning.important + .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.note .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.note .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-warning.seealso + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.seealso .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.tip .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-warning.tip .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert.wy-alert-warning + .admonition-title, +html[data-theme='dark'] + .wy-alert.wy-alert-warning + .rst-content + .admonition-title, +html[data-theme='dark'] .wy-alert.wy-alert-warning .wy-alert-title { + background-color: #803b00; +} + +html[data-theme='dark'] .rst-content .danger, +html[data-theme='dark'] .rst-content .error, +html[data-theme='dark'] .rst-content .wy-alert-danger.admonition, +html[data-theme='dark'] .rst-content .wy-alert-danger.admonition-todo, +html[data-theme='dark'] .rst-content .wy-alert-danger.attention, +html[data-theme='dark'] .rst-content .wy-alert-danger.caution, +html[data-theme='dark'] .rst-content .wy-alert-danger.hint, +html[data-theme='dark'] .rst-content .wy-alert-danger.important, +html[data-theme='dark'] .rst-content .wy-alert-danger.note, +html[data-theme='dark'] .rst-content .wy-alert-danger.seealso, +html[data-theme='dark'] .rst-content .wy-alert-danger.tip, +html[data-theme='dark'] .rst-content .wy-alert-danger.warning, +html[data-theme='dark'] .wy-alert.wy-alert-danger { + background-color: #82231a; +} + +html[data-theme='dark'] .rst-content .danger .admonition-title, +html[data-theme='dark'] .rst-content .danger .wy-alert-title, +html[data-theme='dark'] .rst-content .error .admonition-title, +html[data-theme='dark'] .rst-content .error .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-danger.admonition-todo + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-danger.admonition-todo + .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-danger.admonition + .admonition-title, +html[data-theme='dark'] + .rst-content + .wy-alert-danger.admonition + .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-danger.attention + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.attention .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.caution .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.caution .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.hint .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.hint .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert-danger.important + .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.important .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.note .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.note .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.seealso .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.seealso .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.tip .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.tip .wy-alert-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.warning .admonition-title, +html[data-theme='dark'] .rst-content .wy-alert-danger.warning .wy-alert-title, +html[data-theme='dark'] + .rst-content + .wy-alert.wy-alert-danger + .admonition-title, +html[data-theme='dark'] + .wy-alert.wy-alert-danger + .rst-content + .admonition-title, +html[data-theme='dark'] .wy-alert.wy-alert-danger .wy-alert-title { + background-color: #b9372b; +} + +html[data-theme='dark'] .wy-nav-top { + background-color: #0b152d; +} + +html[data-theme='dark'] .rst-content table.docutils thead, +html[data-theme='dark'] .rst-content table.field-list thead, +html[data-theme='dark'] .wy-table thead { + color: var(--dark-text-color); +} + +html[data-theme='dark'] + .rst-content + table.docutils:not(.field-list) + tr:nth-child(2n-1) + td, +html[data-theme='dark'] .wy-table-backed, +html[data-theme='dark'] html[data-theme='dark'] .wy-table-odd td, +html[data-theme='dark'] .wy-table-striped tr:nth-child(2n-1) td { + background-color: #181818; +} + +html[data-theme='dark'] .rst-content table.docutils td, +html[data-theme='dark'] .wy-table-bordered-all td, +html[data-theme='dark'].writer-html5 .rst-content table.docutils th, +html[data-theme='dark'] .rst-content table.docutils, +html[data-theme='dark'] .wy-table-bordered-all { + border-color: #262626; +} + +html[data-theme='dark'] .rst-content table.docutils caption, +html[data-theme='dark'] .rst-content table.field-list caption, +html[data-theme='dark'] .wy-table caption { + color: var(--dark-text-color); +} + +html[data-theme='dark'] .wy-menu-vertical li.toctree-l3.current > a, +html[data-theme='dark'] + .wy-menu-vertical + li.toctree-l3.current + li.toctree-l4 + > a { + background-color: #18181a; +} diff --git a/_static/dark_mode_css/general.css b/_static/dark_mode_css/general.css new file mode 100644 index 00000000000..aa614f8178e --- /dev/null +++ b/_static/dark_mode_css/general.css @@ -0,0 +1,68 @@ +input[type='color'], +input[type='date'], +input[type='datetime-local'], +input[type='datetime'], +input[type='email'], +input[type='month'], +input[type='number'], +input[type='password'], +input[type='search'], +input[type='tel'], +input[type='text'], +input[type='time'], +input[type='url'], +input[type='week'] { + box-shadow: none; +} + +.theme-switcher { + border-radius: 50%; + position: fixed; + right: 1.6em; + bottom: 1.4em; + z-index: 3; + border: none; + height: 2.2em; + width: 2.2em; + background-color: #fcfcfc; + font-size: 20px; + -webkit-box-shadow: 0px 3px 14px 4px rgba(0, 0, 0, 0.62); + box-shadow: 0px 3px 14px 4px rgba(0, 0, 0, 0.62); + color: #404040; + transition: all 0.3s ease-in-out; +} + +body, +.wy-nav-content-wrap, +.wy-nav-content, +.section, +.highlight, +.rst-content div[class^='highlight'], +.wy-nav-content a, +.btn-neutral, +.btn, +footer, +.wy-nav-side, +.wy-menu-vertical li, +.wy-menu-vertical a, +.wy-side-nav-search .wy-dropdown, +.wy-side-nav-search a, +.wy-side-nav-search input, +html.writer-html4 .rst-content dl:not(.docutils) > dt, +html.writer-html5 + .rst-content + dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) + > dt, +.rst-content code, +.rst-content tt, +html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt, +html.writer-html5 + .rst-content + dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) + dl:not(.field-list) + > dt, +code, +.rst-content code.xref, +.rst-content tt.xref { + transition: all 0.2s ease-in-out; +} diff --git a/_static/dark_mode_js/default_dark.js b/_static/dark_mode_js/default_dark.js new file mode 100644 index 00000000000..ea63e07258e --- /dev/null +++ b/_static/dark_mode_js/default_dark.js @@ -0,0 +1,13 @@ +const loadTheme = () => { + let theme = localStorage.getItem('theme'); + + if (theme !== null) { + if (theme === 'dark') + document.documentElement.setAttribute('data-theme', 'dark'); + } else { + localStorage.setItem('theme', 'dark'); + document.documentElement.setAttribute('data-theme', 'dark'); + } +}; + +loadTheme(); diff --git a/_static/dark_mode_js/default_light.js b/_static/dark_mode_js/default_light.js new file mode 100644 index 00000000000..2b19f92eab9 --- /dev/null +++ b/_static/dark_mode_js/default_light.js @@ -0,0 +1,13 @@ +const loadTheme = () => { + let theme = localStorage.getItem('theme'); + + if (theme !== null) { + if (theme === 'dark') + document.documentElement.setAttribute('data-theme', 'dark'); + } else { + localStorage.setItem('theme', 'light'); + document.documentElement.setAttribute('data-theme', 'light'); + } +}; + +loadTheme(); diff --git a/_static/dark_mode_js/theme_switcher.js b/_static/dark_mode_js/theme_switcher.js new file mode 100644 index 00000000000..860bd5d7e04 --- /dev/null +++ b/_static/dark_mode_js/theme_switcher.js @@ -0,0 +1,39 @@ +const createThemeSwitcher = () => { + let btn = document.createElement('BUTTON'); + btn.className = 'theme-switcher'; + btn.id = 'themeSwitcher'; + btn.innerHTML = + '<i id=themeMoon class="fa fa-moon-o"></i><i id=themeSun class="fa fa-sun-o"></i>'; + document.body.appendChild(btn); + + if (localStorage.getItem('theme') === 'dark') $('#themeMoon').hide(0); + else $('#themeSun').hide(0); +}; + +$(document).ready(() => { + createThemeSwitcher(); + $('#themeSwitcher').click(switchTheme); + + $('footer').html( + $('footer').html() + + 'Dark theme provided by <a href="http://mrdogebro.com">MrDogeBro</a>.' + ); +}); + +const switchTheme = () => { + if (localStorage.getItem('theme') === 'dark') { + localStorage.setItem('theme', 'light'); + document.documentElement.setAttribute('data-theme', 'light'); + + $('#themeSun').fadeOut(200, () => { + $('#themeMoon').fadeIn(200); + }); + } else { + localStorage.setItem('theme', 'dark'); + document.documentElement.setAttribute('data-theme', 'dark'); + + $('#themeMoon').fadeOut(200, () => { + $('#themeSun').fadeIn(200); + }); + } +}; diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000000..8cbf1b161a6 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,323 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('<a class="headerlink">\u00B6</a>'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('<a class="headerlink">\u00B6</a>'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('<p class="highlight-link"><a href="javascript:Documentation.' + + 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000000..4daa6b50bdf --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000000..a858a410e4f Binary files /dev/null and b/_static/file.png differ diff --git a/icon.png b/_static/icon.png similarity index 100% rename from icon.png rename to _static/icon.png diff --git a/_static/img/doc_ci.png b/_static/img/doc_ci.png new file mode 100644 index 00000000000..a9a73f7e927 Binary files /dev/null and b/_static/img/doc_ci.png differ diff --git a/_static/jquery-3.5.1.js b/_static/jquery-3.5.1.js new file mode 100644 index 00000000000..50937333b99 --- /dev/null +++ b/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML <object> elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" + + "<select id='" + expando + "-\r\\' msallowcapture=''>" + + "<option selected=''></option></select>"; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "<a href='' disabled='disabled'></a>" + + "<select disabled='disabled'><option/></select>"; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = "<a href='#'></a>"; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = "<input/>"; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // <object> elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = "<textarea>x</textarea>"; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces <option> tags with their contents when inserted outside of + // the select element. + div.innerHTML = "<option></option>"; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting <tbody> or other required elements. + thead: [ 1, "<table>", "</table>" ], + col: [ 2, "<table><colgroup>", "</colgroup></table>" ], + tr: [ 2, "<table><tbody>", "</tbody></table>" ], + td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG <use> instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /<script|<style|<link/i, + + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( "<script>" ) + .attr( s.scriptAttrs || {} ) + .prop( { charset: s.scriptCharset, src: s.url } ) + .on( "load error", callback = function( evt ) { + script.remove(); + callback = null; + if ( evt ) { + complete( evt.type === "error" ? 404 : 200, evt.type ); + } + } ); + + // Use native DOM manipulation to avoid our domManip AJAX trickery + document.head.appendChild( script[ 0 ] ); + }, + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +var oldCallbacks = [], + rjsonp = /(=)\?(?=&|$)|\?\?/; + +// Default jsonp settings +jQuery.ajaxSetup( { + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) ); + this[ callback ] = true; + return callback; + } +} ); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? + "url" : + typeof s.data === "string" && + ( s.contentType || "" ) + .indexOf( "application/x-www-form-urlencoded" ) === 0 && + rjsonp.test( s.data ) && "data" + ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + + // Insert callback into url or form data + if ( jsonProp ) { + s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); + } else if ( s.jsonp !== false ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters[ "script json" ] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // Force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + overwritten = window[ callbackName ]; + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always( function() { + + // If previous value didn't exist - remove it + if ( overwritten === undefined ) { + jQuery( window ).removeProp( callbackName ); + + // Otherwise restore preexisting value + } else { + window[ callbackName ] = overwritten; + } + + // Save back as free + if ( s[ callbackName ] ) { + + // Make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // Save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + } ); + + // Delegate to script + return "script"; + } +} ); + + + + +// Support: Safari 8 only +// In Safari 8 documents created via document.implementation.createHTMLDocument +// collapse sibling forms: the second one becomes a child of the first one. +// Because of that, this security measure has to be disabled in Safari 8. +// https://bugs.webkit.org/show_bug.cgi?id=137337 +support.createHTMLDocument = ( function() { + var body = document.implementation.createHTMLDocument( "" ).body; + body.innerHTML = "<form></form><form></form>"; + return body.childNodes.length === 2; +} )(); + + +// Argument "data" should be string of html +// context (optional): If specified, the fragment will be created in this context, +// defaults to document +// keepScripts (optional): If true, will include scripts passed in the html string +jQuery.parseHTML = function( data, context, keepScripts ) { + if ( typeof data !== "string" ) { + return []; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + + var base, parsed, scripts; + + if ( !context ) { + + // Stop scripts or inline event handlers from being executed immediately + // by using document.implementation + if ( support.createHTMLDocument ) { + context = document.implementation.createHTMLDocument( "" ); + + // Set the base href for the created document + // so any parsed elements with URLs + // are based on the document's URL (gh-2965) + base = context.createElement( "base" ); + base.href = document.location.href; + context.head.appendChild( base ); + } else { + context = document; + } + } + + parsed = rsingleTag.exec( data ); + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[ 1 ] ) ]; + } + + parsed = buildFragment( [ data ], context, scripts ); + + if ( scripts && scripts.length ) { + jQuery( scripts ).remove(); + } + + return jQuery.merge( [], parsed.childNodes ); +}; + + +/** + * Load a url into a page + */ +jQuery.fn.load = function( url, params, callback ) { + var selector, type, response, + self = this, + off = url.indexOf( " " ); + + if ( off > -1 ) { + selector = stripAndCollapse( url.slice( off ) ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // If we have elements to modify, make the request + if ( self.length > 0 ) { + jQuery.ajax( { + url: url, + + // If "type" variable is undefined, then "GET" method will be used. + // Make value of this field explicit since + // user can override it through ajaxSetup method + type: type || "GET", + dataType: "html", + data: params + } ).done( function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + self.html( selector ? + + // If a selector was specified, locate the right elements in a dummy div + // Exclude scripts to avoid IE 'Permission Denied' errors + jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : + + // Otherwise use the full result + responseText ); + + // If the request succeeds, this function gets "data", "status", "jqXHR" + // but they are ignored because response was set above. + // If it fails, this function gets "jqXHR", "status", "error" + } ).always( callback && function( jqXHR, status ) { + self.each( function() { + callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); + } ); + } ); + } + + return this; +}; + + + + +jQuery.expr.pseudos.animated = function( elem ) { + return jQuery.grep( jQuery.timers, function( fn ) { + return elem === fn.elem; + } ).length; +}; + + + + +jQuery.offset = { + setOffset: function( elem, options, i ) { + var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, + position = jQuery.css( elem, "position" ), + curElem = jQuery( elem ), + props = {}; + + // Set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + curOffset = curElem.offset(); + curCSSTop = jQuery.css( elem, "top" ); + curCSSLeft = jQuery.css( elem, "left" ); + calculatePosition = ( position === "absolute" || position === "fixed" ) && + ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; + + // Need to be able to calculate position if either + // top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( isFunction( options ) ) { + + // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) + options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + + } else { + if ( typeof props.top === "number" ) { + props.top += "px"; + } + if ( typeof props.left === "number" ) { + props.left += "px"; + } + curElem.css( props ); + } + } +}; + +jQuery.fn.extend( { + + // offset() relates an element's border box to the document origin + offset: function( options ) { + + // Preserve chaining for setter + if ( arguments.length ) { + return options === undefined ? + this : + this.each( function( i ) { + jQuery.offset.setOffset( this, options, i ); + } ); + } + + var rect, win, + elem = this[ 0 ]; + + if ( !elem ) { + return; + } + + // Return zeros for disconnected and hidden (display: none) elements (gh-2310) + // Support: IE <=11 only + // Running getBoundingClientRect on a + // disconnected node in IE throws an error + if ( !elem.getClientRects().length ) { + return { top: 0, left: 0 }; + } + + // Get document-relative position by adding viewport scroll to viewport-relative gBCR + rect = elem.getBoundingClientRect(); + win = elem.ownerDocument.defaultView; + return { + top: rect.top + win.pageYOffset, + left: rect.left + win.pageXOffset + }; + }, + + // position() relates an element's margin box to its offset parent's padding box + // This corresponds to the behavior of CSS absolute positioning + position: function() { + if ( !this[ 0 ] ) { + return; + } + + var offsetParent, offset, doc, + elem = this[ 0 ], + parentOffset = { top: 0, left: 0 }; + + // position:fixed elements are offset from the viewport, which itself always has zero offset + if ( jQuery.css( elem, "position" ) === "fixed" ) { + + // Assume position:fixed implies availability of getBoundingClientRect + offset = elem.getBoundingClientRect(); + + } else { + offset = this.offset(); + + // Account for the *real* offset parent, which can be the document or its root element + // when a statically positioned element is identified + doc = elem.ownerDocument; + offsetParent = elem.offsetParent || doc.documentElement; + while ( offsetParent && + ( offsetParent === doc.body || offsetParent === doc.documentElement ) && + jQuery.css( offsetParent, "position" ) === "static" ) { + + offsetParent = offsetParent.parentNode; + } + if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) { + + // Incorporate borders into its offset, since they are outside its content origin + parentOffset = jQuery( offsetParent ).offset(); + parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true ); + parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true ); + } + } + + // Subtract parent offsets and element margins + return { + top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), + left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) + }; + }, + + // This method will return documentElement in the following cases: + // 1) For the element inside the iframe without offsetParent, this method will return + // documentElement of the parent window + // 2) For the hidden or detached element + // 3) For body or html element, i.e. in case of the html node - it will return itself + // + // but those exceptions were never presented as a real life use-cases + // and might be considered as more preferable results. + // + // This logic, however, is not guaranteed and can change at any point in the future + offsetParent: function() { + return this.map( function() { + var offsetParent = this.offsetParent; + + while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { + offsetParent = offsetParent.offsetParent; + } + + return offsetParent || documentElement; + } ); + } +} ); + +// Create scrollLeft and scrollTop methods +jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { + var top = "pageYOffset" === prop; + + jQuery.fn[ method ] = function( val ) { + return access( this, function( elem, method, val ) { + + // Coalesce documents and windows + var win; + if ( isWindow( elem ) ) { + win = elem; + } else if ( elem.nodeType === 9 ) { + win = elem.defaultView; + } + + if ( val === undefined ) { + return win ? win[ prop ] : elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : win.pageXOffset, + top ? val : win.pageYOffset + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length ); + }; +} ); + +// Support: Safari <=7 - 9.1, Chrome <=37 - 49 +// Add the top/left cssHooks using jQuery.fn.position +// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 +// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 +// getComputedStyle returns percent when specified for top/left/bottom/right; +// rather than make the css module depend on the offset module, just check for it here +jQuery.each( [ "top", "left" ], function( _i, prop ) { + jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, + function( elem, computed ) { + if ( computed ) { + computed = curCSS( elem, prop ); + + // If curCSS returns percentage, fallback to offset + return rnumnonpx.test( computed ) ? + jQuery( elem ).position()[ prop ] + "px" : + computed; + } + } + ); +} ); + + +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, + function( defaultExtra, funcName ) { + + // Margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return access( this, function( elem, type, value ) { + var doc; + + if ( isWindow( elem ) ) { + + // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) + return funcName.indexOf( "outer" ) === 0 ? + elem[ "inner" + name ] : + elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], + // whichever is greatest + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable ); + }; + } ); +} ); + + +jQuery.each( [ + "ajaxStart", + "ajaxStop", + "ajaxComplete", + "ajaxError", + "ajaxSuccess", + "ajaxSend" +], function( _i, type ) { + jQuery.fn[ type ] = function( fn ) { + return this.on( type, fn ); + }; +} ); + + + + +jQuery.fn.extend( { + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? + this.off( selector, "**" ) : + this.off( types, selector || "**", fn ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( _i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + } ); + + + + +// Support: Android <=4.0 only +// Make sure we trim BOM and NBSP +var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + +// Bind a function to a context, optionally partially applying any +// arguments. +// jQuery.proxy is deprecated to promote standards (specifically Function#bind) +// However, it is not slated for removal any time soon +jQuery.proxy = function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; +}; + +jQuery.holdReady = function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } +}; +jQuery.isArray = Array.isArray; +jQuery.parseJSON = JSON.parse; +jQuery.nodeName = nodeName; +jQuery.isFunction = isFunction; +jQuery.isWindow = isWindow; +jQuery.camelCase = camelCase; +jQuery.type = toType; + +jQuery.now = Date.now; + +jQuery.isNumeric = function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); +}; + +jQuery.trim = function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); +}; + + + +// Register as a named AMD module, since jQuery can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase jquery is used because AMD module names are +// derived from file names, and jQuery is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + +if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function() { + return jQuery; + } ); +} + + + + +var + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$; + +jQuery.noConflict = function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; +}; + +// Expose jQuery and $ identifiers, even in AMD +// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) +// and CommonJS for browser emulators (#13566) +if ( typeof noGlobal === "undefined" ) { + window.jQuery = window.$ = jQuery; +} + + + + +return jQuery; +} ); diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 00000000000..b0614034ad3 --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(D).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\s*(?:[^=]|=\s*.checked.)/i,je=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(je,""),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px",t.style.height="1px",n.style.height="9px",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=["Webkit","Moz","ms"],ze=E.createElement("div").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:"absolute",visibility:"hidden",display:"block"},Qe={letterSpacing:"0",fontWeight:"400"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Qe&&(i=Qe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt("show"),slideUp:lt("hide"),slideToggle:lt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement("input"),it=E.createElement("select").appendChild(E.createElement("option")),rt.type="checkbox",y.checkOn=""!==rt.value,y.optSelected=it.selected,(rt=E.createElement("input")).value="t",rt.type="radio",y.radioValue="t"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function mt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr("class","");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=yt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+vt(yt(n))+" ").indexOf(t))return!0;return!1}});var xt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(xt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:vt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||S.error("Invalid XML: "+e),t};var St=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)Dt(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\/\//,Rt={},Mt={},It="*/".concat("*"),Wt=E.createElement("a");function Ft(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":It,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+"//"+Wt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(jt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Et.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,"$1"),o=(Et.test(f)?"&":"?")+"_="+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+It+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&"withCredentials"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Gt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S}); diff --git a/_static/js/badge_only.js b/_static/js/badge_only.js new file mode 100644 index 00000000000..526d7234b65 --- /dev/null +++ b/_static/js/badge_only.js @@ -0,0 +1 @@ +!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); \ No newline at end of file diff --git a/_static/js/html5shiv-printshiv.min.js b/_static/js/html5shiv-printshiv.min.js new file mode 100644 index 00000000000..2b43bd062e9 --- /dev/null +++ b/_static/js/html5shiv-printshiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 00000000000..cd1c674f5e3 --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 00000000000..1fddb6ee4a6 --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("<div class='wy-table-responsive'></div>"),n("table.docutils.footnote").wrap("<div class='wy-table-responsive footnote'></div>"),n("table.docutils.citation").wrap("<div class='wy-table-responsive citation'></div>"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n('<button class="toctree-expand" title="Open/close menu"></button>'),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t<e.length&&!window.requestAnimationFrame;++t)window.requestAnimationFrame=window[e[t]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[e[t]+"CancelAnimationFrame"]||window[e[t]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(e,t){var i=(new Date).getTime(),o=Math.max(0,16-(i-n)),r=window.setTimeout((function(){e(i+o)}),o);return n=i+o,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()}).call(window)},function(n,e){n.exports=jQuery},function(n,e,t){}]); \ No newline at end of file diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000000..863704b310d --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,297 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + + + +var splitChars = (function() { + var result = {}; + var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648, + 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702, + 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971, + 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345, + 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761, + 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823, + 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125, + 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695, + 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587, + 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141]; + var i, j, start, end; + for (i = 0; i < singles.length; i++) { + result[singles[i]] = true; + } + var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709], + [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161], + [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568], + [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807], + [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047], + [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383], + [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450], + [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547], + [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673], + [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820], + [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946], + [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023], + [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173], + [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332], + [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481], + [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718], + [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791], + [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095], + [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205], + [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687], + [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968], + [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869], + [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102], + [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271], + [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592], + [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822], + [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167], + [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959], + [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143], + [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318], + [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483], + [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101], + [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567], + [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292], + [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444], + [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783], + [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311], + [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511], + [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774], + [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071], + [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263], + [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519], + [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647], + [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967], + [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295], + [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274], + [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007], + [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381], + [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]]; + for (i = 0; i < ranges.length; i++) { + start = ranges[i][0]; + end = ranges[i][1]; + for (j = start; j <= end; j++) { + result[j] = true; + } + } + return result; +})(); + +function splitQuery(query) { + var result = []; + var start = -1; + for (var i = 0; i < query.length; i++) { + if (splitChars[query.charCodeAt(i)]) { + if (start !== -1) { + result.push(query.slice(start, i)); + start = -1; + } + } else if (start === -1) { + start = i; + } + } + if (start !== -1) { + result.push(query.slice(start)); + } + return result; +} + + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 00000000000..d96755fdaf8 Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plot_directive.css b/_static/plot_directive.css new file mode 100644 index 00000000000..d45593c93c9 --- /dev/null +++ b/_static/plot_directive.css @@ -0,0 +1,16 @@ +/* + * plot_directive.css + * ~~~~~~~~~~~~ + * + * Stylesheet controlling images created using the `plot` directive within + * Sphinx. + * + * :copyright: Copyright 2020-* by the Matplotlib development team. + * :license: Matplotlib, see LICENSE for details. + * + */ + +img.plot-directive { + border: 0; + max-width: 100%; +} diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000000..7107cec93a9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000000..691aeb82d00 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,74 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000000..002e9c4a20f --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,529 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +if (!Scorer) { + /** + * Simple result scoring code. + */ + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2 + }; +} + +if (!splitQuery) { + function splitQuery(query) { + return query.split(/\s+/); + } +} + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + htmlToText : function(htmlString) { + var virtualDocument = document.implementation.createHTMLDocument('virtual'); + var htmlElement = $(htmlString, virtualDocument); + htmlElement.find('.headerlink').remove(); + docContent = htmlElement.find('[role=main]')[0]; + if(docContent === undefined) { + console.warn("Content block not found. Sphinx search tries to obtain it " + + "via '[role=main]'. Could you check your theme or template."); + return ""; + } + return docContent.textContent || docContent.innerText; + }, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out); + this.dots = $('<span></span>').appendTo(this.title); + this.status = $('<p class="search-summary"> </p>').appendTo(this.out); + this.output = $('<ul class="search"/>').appendTo(this.out); + + $('#search-progress').text(_('Preparing search...')); + this.startPulse(); + + // index already loaded, the browser was quick! + if (this.hasIndex()) + this.query(query); + else + this.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query : function(query) { + var i; + + // stem the searchterms and add them to the correct list + var stemmer = new Stemmer(); + var searchterms = []; + var excluded = []; + var hlterms = []; + var tmp = splitQuery(query); + var objectterms = []; + for (i = 0; i < tmp.length; i++) { + if (tmp[i] !== "") { + objectterms.push(tmp[i].toLowerCase()); + } + + if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i] === "") { + // skip this "word" + continue; + } + // stem the word + var word = stemmer.stemWord(tmp[i].toLowerCase()); + // prevent stemmer from cutting word smaller than two chars + if(word.length < 3 && tmp[i].length >= 3) { + word = tmp[i]; + } + var toAppend; + // select the correct list + if (word[0] == '-') { + toAppend = excluded; + word = word.substr(1); + } + else { + toAppend = searchterms; + hlterms.push(tmp[i].toLowerCase()); + } + // only add if not already in the list + if (!$u.contains(toAppend, word)) + toAppend.push(word); + } + var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" ")); + + // console.debug('SEARCH: searching for:'); + // console.info('required: ', searchterms); + // console.info('excluded: ', excluded); + + // prepare search + var terms = this._index.terms; + var titleterms = this._index.titleterms; + + // array of [filename, title, anchor, descr, score] + var results = []; + $('#search-progress').empty(); + + // lookup as object + for (i = 0; i < objectterms.length; i++) { + var others = [].concat(objectterms.slice(0, i), + objectterms.slice(i+1, objectterms.length)); + results = results.concat(this.performObjectSearch(objectterms[i], others)); + } + + // lookup as search terms in fulltext + results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + for (i = 0; i < results.length; i++) + results[i][4] = Scorer.score(results[i]); + } + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort(function(a, b) { + var left = a[4]; + var right = b[4]; + if (left > right) { + return 1; + } else if (left < right) { + return -1; + } else { + // same score: sort alphabetically + left = a[1].toLowerCase(); + right = b[1].toLowerCase(); + return (left > right) ? -1 : ((left < right) ? 1 : 0); + } + }); + + // for debugging + //Search.lastresults = results.slice(); // a copy + //console.info('search results:', Search.lastresults); + + // print the results + var resultCount = results.length; + function displayNextItem() { + // results left, load the summary and display it + if (results.length) { + var item = results.pop(); + var listItem = $('<li></li>'); + var requestUrl = ""; + var linkUrl = ""; + if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') { + // dirhtml builder + var dirname = item[0] + '/'; + if (dirname.match(/\/index\/$/)) { + dirname = dirname.substring(0, dirname.length-6); + } else if (dirname == 'index/') { + dirname = ''; + } + requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + dirname; + linkUrl = requestUrl; + + } else { + // normal html builders + requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX; + linkUrl = item[0] + DOCUMENTATION_OPTIONS.LINK_SUFFIX; + } + listItem.append($('<a/>').attr('href', + linkUrl + + highlightstring + item[2]).html(item[1])); + if (item[3]) { + listItem.append($('<span> (' + item[3] + ')</span>')); + Search.output.append(listItem); + setTimeout(function() { + displayNextItem(); + }, 5); + } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { + $.ajax({url: requestUrl, + dataType: "text", + complete: function(jqxhr, textstatus) { + var data = jqxhr.responseText; + if (data !== '' && data !== undefined) { + var summary = Search.makeSearchSummary(data, searchterms, hlterms); + if (summary) { + listItem.append(summary); + } + } + Search.output.append(listItem); + setTimeout(function() { + displayNextItem(); + }, 5); + }}); + } else { + // no source available, just display title + Search.output.append(listItem); + setTimeout(function() { + displayNextItem(); + }, 5); + } + } + // search finished, update title and status message + else { + Search.stopPulse(); + Search.title.text(_('Search Results')); + if (!resultCount) + Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.')); + else + Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount)); + Search.status.fadeIn(500); + } + } + displayNextItem(); + }, + + /** + * search for object names + */ + performObjectSearch : function(object, otherterms) { + var filenames = this._index.filenames; + var docnames = this._index.docnames; + var objects = this._index.objects; + var objnames = this._index.objnames; + var titles = this._index.titles; + + var i; + var results = []; + + for (var prefix in objects) { + for (var iMatch = 0; iMatch != objects[prefix].length; ++iMatch) { + var match = objects[prefix][iMatch]; + var name = match[4]; + var fullname = (prefix ? prefix + '.' : '') + name; + var fullnameLower = fullname.toLowerCase() + if (fullnameLower.indexOf(object) > -1) { + var score = 0; + var parts = fullnameLower.split('.'); + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower == object || parts[parts.length - 1] == object) { + score += Scorer.objNameMatch; + // matches in last name + } else if (parts[parts.length - 1].indexOf(object) > -1) { + score += Scorer.objPartialMatch; + } + var objname = objnames[match[1]][2]; + var title = titles[match[0]]; + // If more than one term searched for, we require other words to be + // found in the name/title/description + if (otherterms.length > 0) { + var haystack = (prefix + ' ' + name + ' ' + + objname + ' ' + title).toLowerCase(); + var allfound = true; + for (i = 0; i < otherterms.length; i++) { + if (haystack.indexOf(otherterms[i]) == -1) { + allfound = false; + break; + } + } + if (!allfound) { + continue; + } + } + var descr = objname + _(', in ') + title; + + var anchor = match[3]; + if (anchor === '') + anchor = fullname; + else if (anchor == '-') + anchor = objnames[match[1]][1] + '-' + fullname; + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) { + score += Scorer.objPrio[match[2]]; + } else { + score += Scorer.objPrioDefault; + } + results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]); + } + } + } + + return results; + }, + + /** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + */ + escapeRegExp : function(string) { + return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch : function(searchterms, excluded, terms, titleterms) { + var docnames = this._index.docnames; + var filenames = this._index.filenames; + var titles = this._index.titles; + + var i, j, file; + var fileMap = {}; + var scoreMap = {}; + var results = []; + + // perform the search on the required terms + for (i = 0; i < searchterms.length; i++) { + var word = searchterms[i]; + var files = []; + var _o = [ + {files: terms[word], score: Scorer.term}, + {files: titleterms[word], score: Scorer.title} + ]; + // add support for partial matches + if (word.length > 2) { + var word_regex = this.escapeRegExp(word); + for (var w in terms) { + if (w.match(word_regex) && !terms[word]) { + _o.push({files: terms[w], score: Scorer.partialTerm}) + } + } + for (var w in titleterms) { + if (w.match(word_regex) && !titleterms[word]) { + _o.push({files: titleterms[w], score: Scorer.partialTitle}) + } + } + } + + // no match but word was a required one + if ($u.every(_o, function(o){return o.files === undefined;})) { + break; + } + // found search word in contents + $u.each(_o, function(o) { + var _files = o.files; + if (_files === undefined) + return + + if (_files.length === undefined) + _files = [_files]; + files = files.concat(_files); + + // set score for the word in each file to Scorer.term + for (j = 0; j < _files.length; j++) { + file = _files[j]; + if (!(file in scoreMap)) + scoreMap[file] = {}; + scoreMap[file][word] = o.score; + } + }); + + // create the mapping + for (j = 0; j < files.length; j++) { + file = files[j]; + if (file in fileMap && fileMap[file].indexOf(word) === -1) + fileMap[file].push(word); + else + fileMap[file] = [word]; + } + } + + // now check if the files don't contain excluded terms + for (file in fileMap) { + var valid = true; + + // check if all requirements are matched + var filteredTermCount = // as search terms with length < 3 are discarded: ignore + searchterms.filter(function(term){return term.length > 2}).length + if ( + fileMap[file].length != searchterms.length && + fileMap[file].length != filteredTermCount + ) continue; + + // ensure that none of the excluded terms is in the search result + for (i = 0; i < excluded.length; i++) { + if (terms[excluded[i]] == file || + titleterms[excluded[i]] == file || + $u.contains(terms[excluded[i]] || [], file) || + $u.contains(titleterms[excluded[i]] || [], file)) { + valid = false; + break; + } + } + + // if we have still a valid result we can add it to the result list + if (valid) { + // select one (max) score for the file. + // for better ranking, we should calculate ranking by using words statistics like basic tf-idf... + var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]})); + results.push([docnames[file], titles[file], '', null, score, filenames[file]]); + } + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words, hlwords is the list of normal, unstemmed + * words. the first one is used to find the occurrence, the + * latter for highlighting it. + */ + makeSearchSummary : function(htmlText, keywords, hlwords) { + var text = Search.htmlToText(htmlText); + if (text == "") { + return null; + } + var textLower = text.toLowerCase(); + var start = 0; + $.each(keywords, function() { + var i = textLower.indexOf(this.toLowerCase()); + if (i > -1) + start = i; + }); + start = Math.max(start - 120, 0); + var excerpt = ((start > 0) ? '...' : '') + + $.trim(text.substr(start, 240)) + + ((start + 240 - text.length) ? '...' : ''); + var rv = $('<p class="context"></p>').text(excerpt); + $.each(hlwords, function() { + rv = rv.highlightText(this, 'highlighted'); + }); + return rv; + } +}; + +$(document).ready(function() { + Search.init(); +}); diff --git a/_static/underscore-1.13.1.js b/_static/underscore-1.13.1.js new file mode 100644 index 00000000000..ffd77af9648 --- /dev/null +++ b/_static/underscore-1.13.1.js @@ -0,0 +1,2042 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define('underscore', factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () { + var current = global._; + var exports = global._ = factory(); + exports.noConflict = function () { global._ = current; return exports; }; + }())); +}(this, (function () { + // Underscore.js 1.13.1 + // https://underscorejs.org + // (c) 2009-2021 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors + // Underscore may be freely distributed under the MIT license. + + // Current version. + var VERSION = '1.13.1'; + + // Establish the root object, `window` (`self`) in the browser, `global` + // on the server, or `this` in some virtual machines. We use `self` + // instead of `window` for `WebWorker` support. + var root = typeof self == 'object' && self.self === self && self || + typeof global == 'object' && global.global === global && global || + Function('return this')() || + {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype; + var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; + + // Create quick reference variables for speed access to core prototypes. + var push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // Modern feature detection. + var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', + supportsDataView = typeof DataView !== 'undefined'; + + // All **ECMAScript 5+** native function implementations that we hope to use + // are declared here. + var nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeCreate = Object.create, + nativeIsView = supportsArrayBuffer && ArrayBuffer.isView; + + // Create references to these builtin functions because we override them. + var _isNaN = isNaN, + _isFinite = isFinite; + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + // The largest integer that can be represented exactly. + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + + // Some functions take a variable number of arguments, or a few expected + // arguments at the beginning and then a variable number of values to operate + // on. This helper accumulates all remaining arguments past the function’s + // argument length (or an explicit `startIndex`), into an array that becomes + // the last argument. Similar to ES6’s "rest parameter". + function restArguments(func, startIndex) { + startIndex = startIndex == null ? func.length - 1 : +startIndex; + return function() { + var length = Math.max(arguments.length - startIndex, 0), + rest = Array(length), + index = 0; + for (; index < length; index++) { + rest[index] = arguments[index + startIndex]; + } + switch (startIndex) { + case 0: return func.call(this, rest); + case 1: return func.call(this, arguments[0], rest); + case 2: return func.call(this, arguments[0], arguments[1], rest); + } + var args = Array(startIndex + 1); + for (index = 0; index < startIndex; index++) { + args[index] = arguments[index]; + } + args[startIndex] = rest; + return func.apply(this, args); + }; + } + + // Is a given variable an object? + function isObject(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + } + + // Is a given value equal to null? + function isNull(obj) { + return obj === null; + } + + // Is a given variable undefined? + function isUndefined(obj) { + return obj === void 0; + } + + // Is a given value a boolean? + function isBoolean(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + } + + // Is a given value a DOM element? + function isElement(obj) { + return !!(obj && obj.nodeType === 1); + } + + // Internal function for creating a `toString`-based type tester. + function tagTester(name) { + var tag = '[object ' + name + ']'; + return function(obj) { + return toString.call(obj) === tag; + }; + } + + var isString = tagTester('String'); + + var isNumber = tagTester('Number'); + + var isDate = tagTester('Date'); + + var isRegExp = tagTester('RegExp'); + + var isError = tagTester('Error'); + + var isSymbol = tagTester('Symbol'); + + var isArrayBuffer = tagTester('ArrayBuffer'); + + var isFunction = tagTester('Function'); + + // Optimize `isFunction` if appropriate. Work around some `typeof` bugs in old + // v8, IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). + var nodelist = root.document && root.document.childNodes; + if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') { + isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + var isFunction$1 = isFunction; + + var hasObjectTag = tagTester('Object'); + + // In IE 10 - Edge 13, `DataView` has string tag `'[object Object]'`. + // In IE 11, the most common among them, this problem also applies to + // `Map`, `WeakMap` and `Set`. + var hasStringTagBug = ( + supportsDataView && hasObjectTag(new DataView(new ArrayBuffer(8))) + ), + isIE11 = (typeof Map !== 'undefined' && hasObjectTag(new Map)); + + var isDataView = tagTester('DataView'); + + // In IE 10 - Edge 13, we need a different heuristic + // to determine whether an object is a `DataView`. + function ie10IsDataView(obj) { + return obj != null && isFunction$1(obj.getInt8) && isArrayBuffer(obj.buffer); + } + + var isDataView$1 = (hasStringTagBug ? ie10IsDataView : isDataView); + + // Is a given value an array? + // Delegates to ECMA5's native `Array.isArray`. + var isArray = nativeIsArray || tagTester('Array'); + + // Internal function to check whether `key` is an own property name of `obj`. + function has$1(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + } + + var isArguments = tagTester('Arguments'); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + (function() { + if (!isArguments(arguments)) { + isArguments = function(obj) { + return has$1(obj, 'callee'); + }; + } + }()); + + var isArguments$1 = isArguments; + + // Is a given object a finite number? + function isFinite$1(obj) { + return !isSymbol(obj) && _isFinite(obj) && !isNaN(parseFloat(obj)); + } + + // Is the given value `NaN`? + function isNaN$1(obj) { + return isNumber(obj) && _isNaN(obj); + } + + // Predicate-generating function. Often useful outside of Underscore. + function constant(value) { + return function() { + return value; + }; + } + + // Common internal logic for `isArrayLike` and `isBufferLike`. + function createSizePropertyCheck(getSizeProperty) { + return function(collection) { + var sizeProperty = getSizeProperty(collection); + return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX; + } + } + + // Internal helper to generate a function to obtain property `key` from `obj`. + function shallowProperty(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + } + + // Internal helper to obtain the `byteLength` property of an object. + var getByteLength = shallowProperty('byteLength'); + + // Internal helper to determine whether we should spend extensive checks against + // `ArrayBuffer` et al. + var isBufferLike = createSizePropertyCheck(getByteLength); + + // Is a given value a typed array? + var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/; + function isTypedArray(obj) { + // `ArrayBuffer.isView` is the most future-proof, so use it when available. + // Otherwise, fall back on the above regular expression. + return nativeIsView ? (nativeIsView(obj) && !isDataView$1(obj)) : + isBufferLike(obj) && typedArrayPattern.test(toString.call(obj)); + } + + var isTypedArray$1 = supportsArrayBuffer ? isTypedArray : constant(false); + + // Internal helper to obtain the `length` property of an object. + var getLength = shallowProperty('length'); + + // Internal helper to create a simple lookup structure. + // `collectNonEnumProps` used to depend on `_.contains`, but this led to + // circular imports. `emulatedSet` is a one-off solution that only works for + // arrays of strings. + function emulatedSet(keys) { + var hash = {}; + for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true; + return { + contains: function(key) { return hash[key]; }, + push: function(key) { + hash[key] = true; + return keys.push(key); + } + }; + } + + // Internal helper. Checks `keys` for the presence of keys in IE < 9 that won't + // be iterated by `for key in ...` and thus missed. Extends `keys` in place if + // needed. + function collectNonEnumProps(obj, keys) { + keys = emulatedSet(keys); + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = isFunction$1(constructor) && constructor.prototype || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (has$1(obj, prop) && !keys.contains(prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !keys.contains(prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys`. + function keys(obj) { + if (!isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (has$1(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + } + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + function isEmpty(obj) { + if (obj == null) return true; + // Skip the more expensive `toString`-based type checks if `obj` has no + // `.length`. + var length = getLength(obj); + if (typeof length == 'number' && ( + isArray(obj) || isString(obj) || isArguments$1(obj) + )) return length === 0; + return getLength(keys(obj)) === 0; + } + + // Returns whether an object has a given set of `key:value` pairs. + function isMatch(object, attrs) { + var _keys = keys(attrs), length = _keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = _keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + } + + // If Underscore is called as a function, it returns a wrapped object that can + // be used OO-style. This wrapper holds altered versions of all functions added + // through `_.mixin`. Wrapped objects may be chained. + function _$1(obj) { + if (obj instanceof _$1) return obj; + if (!(this instanceof _$1)) return new _$1(obj); + this._wrapped = obj; + } + + _$1.VERSION = VERSION; + + // Extracts the result from a wrapped and chained object. + _$1.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxies for some methods used in engine operations + // such as arithmetic and JSON stringification. + _$1.prototype.valueOf = _$1.prototype.toJSON = _$1.prototype.value; + + _$1.prototype.toString = function() { + return String(this._wrapped); + }; + + // Internal function to wrap or shallow-copy an ArrayBuffer, + // typed array or DataView to a new view, reusing the buffer. + function toBufferView(bufferSource) { + return new Uint8Array( + bufferSource.buffer || bufferSource, + bufferSource.byteOffset || 0, + getByteLength(bufferSource) + ); + } + + // We use this string twice, so give it a name for minification. + var tagDataView = '[object DataView]'; + + // Internal recursive comparison function for `_.isEqual`. + function eq(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // `null` or `undefined` only equal to itself (strict comparison). + if (a == null || b == null) return false; + // `NaN`s are equivalent, but non-reflexive. + if (a !== a) return b !== b; + // Exhaust primitive checks + var type = typeof a; + if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; + return deepEq(a, b, aStack, bStack); + } + + // Internal recursive comparison function for `_.isEqual`. + function deepEq(a, b, aStack, bStack) { + // Unwrap any wrapped objects. + if (a instanceof _$1) a = a._wrapped; + if (b instanceof _$1) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + // Work around a bug in IE 10 - Edge 13. + if (hasStringTagBug && className == '[object Object]' && isDataView$1(a)) { + if (!isDataView$1(b)) return false; + className = tagDataView; + } + switch (className) { + // These types are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN. + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + case '[object Symbol]': + return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); + case '[object ArrayBuffer]': + case tagDataView: + // Coerce to typed array so we can fall through. + return deepEq(toBufferView(a), toBufferView(b), aStack, bStack); + } + + var areArrays = className === '[object Array]'; + if (!areArrays && isTypedArray$1(a)) { + var byteLength = getByteLength(a); + if (byteLength !== getByteLength(b)) return false; + if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true; + areArrays = true; + } + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor && + isFunction$1(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var _keys = keys(a), key; + length = _keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = _keys[length]; + if (!(has$1(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + } + + // Perform a deep comparison to check if two objects are equal. + function isEqual(a, b) { + return eq(a, b); + } + + // Retrieve all the enumerable property names of an object. + function allKeys(obj) { + if (!isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + } + + // Since the regular `Object.prototype.toString` type tests don't work for + // some types in IE 11, we use a fingerprinting heuristic instead, based + // on the methods. It's not great, but it's the best we got. + // The fingerprint method lists are defined below. + function ie11fingerprint(methods) { + var length = getLength(methods); + return function(obj) { + if (obj == null) return false; + // `Map`, `WeakMap` and `Set` have no enumerable keys. + var keys = allKeys(obj); + if (getLength(keys)) return false; + for (var i = 0; i < length; i++) { + if (!isFunction$1(obj[methods[i]])) return false; + } + // If we are testing against `WeakMap`, we need to ensure that + // `obj` doesn't have a `forEach` method in order to distinguish + // it from a regular `Map`. + return methods !== weakMapMethods || !isFunction$1(obj[forEachName]); + }; + } + + // In the interest of compact minification, we write + // each string in the fingerprints only once. + var forEachName = 'forEach', + hasName = 'has', + commonInit = ['clear', 'delete'], + mapTail = ['get', hasName, 'set']; + + // `Map`, `WeakMap` and `Set` each have slightly different + // combinations of the above sublists. + var mapMethods = commonInit.concat(forEachName, mapTail), + weakMapMethods = commonInit.concat(mapTail), + setMethods = ['add'].concat(commonInit, forEachName, hasName); + + var isMap = isIE11 ? ie11fingerprint(mapMethods) : tagTester('Map'); + + var isWeakMap = isIE11 ? ie11fingerprint(weakMapMethods) : tagTester('WeakMap'); + + var isSet = isIE11 ? ie11fingerprint(setMethods) : tagTester('Set'); + + var isWeakSet = tagTester('WeakSet'); + + // Retrieve the values of an object's properties. + function values(obj) { + var _keys = keys(obj); + var length = _keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[_keys[i]]; + } + return values; + } + + // Convert an object into a list of `[key, value]` pairs. + // The opposite of `_.object` with one argument. + function pairs(obj) { + var _keys = keys(obj); + var length = _keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [_keys[i], obj[_keys[i]]]; + } + return pairs; + } + + // Invert the keys and values of an object. The values must be serializable. + function invert(obj) { + var result = {}; + var _keys = keys(obj); + for (var i = 0, length = _keys.length; i < length; i++) { + result[obj[_keys[i]]] = _keys[i]; + } + return result; + } + + // Return a sorted list of the function names available on the object. + function functions(obj) { + var names = []; + for (var key in obj) { + if (isFunction$1(obj[key])) names.push(key); + } + return names.sort(); + } + + // An internal function for creating assigner functions. + function createAssigner(keysFunc, defaults) { + return function(obj) { + var length = arguments.length; + if (defaults) obj = Object(obj); + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!defaults || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + } + + // Extend a given object with all the properties in passed-in object(s). + var extend = createAssigner(allKeys); + + // Assigns a given object with all the own properties in the passed-in + // object(s). + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + var extendOwn = createAssigner(keys); + + // Fill in a given object with default properties. + var defaults = createAssigner(allKeys, true); + + // Create a naked function reference for surrogate-prototype-swapping. + function ctor() { + return function(){}; + } + + // An internal function for creating a new object that inherits from another. + function baseCreate(prototype) { + if (!isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + var Ctor = ctor(); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + } + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + function create(prototype, props) { + var result = baseCreate(prototype); + if (props) extendOwn(result, props); + return result; + } + + // Create a (shallow-cloned) duplicate of an object. + function clone(obj) { + if (!isObject(obj)) return obj; + return isArray(obj) ? obj.slice() : extend({}, obj); + } + + // Invokes `interceptor` with the `obj` and then returns `obj`. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + function tap(obj, interceptor) { + interceptor(obj); + return obj; + } + + // Normalize a (deep) property `path` to array. + // Like `_.iteratee`, this function can be customized. + function toPath$1(path) { + return isArray(path) ? path : [path]; + } + _$1.toPath = toPath$1; + + // Internal wrapper for `_.toPath` to enable minification. + // Similar to `cb` for `_.iteratee`. + function toPath(path) { + return _$1.toPath(path); + } + + // Internal function to obtain a nested property in `obj` along `path`. + function deepGet(obj, path) { + var length = path.length; + for (var i = 0; i < length; i++) { + if (obj == null) return void 0; + obj = obj[path[i]]; + } + return length ? obj : void 0; + } + + // Get the value of the (deep) property on `path` from `object`. + // If any property in `path` does not exist or if the value is + // `undefined`, return `defaultValue` instead. + // The `path` is normalized through `_.toPath`. + function get(object, path, defaultValue) { + var value = deepGet(object, toPath(path)); + return isUndefined(value) ? defaultValue : value; + } + + // Shortcut function for checking if an object has a given property directly on + // itself (in other words, not on a prototype). Unlike the internal `has` + // function, this public version can also traverse nested properties. + function has(obj, path) { + path = toPath(path); + var length = path.length; + for (var i = 0; i < length; i++) { + var key = path[i]; + if (!has$1(obj, key)) return false; + obj = obj[key]; + } + return !!length; + } + + // Keep the identity function around for default iteratees. + function identity(value) { + return value; + } + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + function matcher(attrs) { + attrs = extendOwn({}, attrs); + return function(obj) { + return isMatch(obj, attrs); + }; + } + + // Creates a function that, when passed an object, will traverse that object’s + // properties down the given `path`, specified as an array of keys or indices. + function property(path) { + path = toPath(path); + return function(obj) { + return deepGet(obj, path); + }; + } + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + function optimizeCb(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + // The 2-argument case is omitted because we’re not using it. + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + } + + // An internal function to generate callbacks that can be applied to each + // element in a collection, returning the desired result — either `_.identity`, + // an arbitrary callback, a property matcher, or a property accessor. + function baseIteratee(value, context, argCount) { + if (value == null) return identity; + if (isFunction$1(value)) return optimizeCb(value, context, argCount); + if (isObject(value) && !isArray(value)) return matcher(value); + return property(value); + } + + // External wrapper for our callback generator. Users may customize + // `_.iteratee` if they want additional predicate/iteratee shorthand styles. + // This abstraction hides the internal-only `argCount` argument. + function iteratee(value, context) { + return baseIteratee(value, context, Infinity); + } + _$1.iteratee = iteratee; + + // The function we call internally to generate a callback. It invokes + // `_.iteratee` if overridden, otherwise `baseIteratee`. + function cb(value, context, argCount) { + if (_$1.iteratee !== iteratee) return _$1.iteratee(value, context); + return baseIteratee(value, context, argCount); + } + + // Returns the results of applying the `iteratee` to each element of `obj`. + // In contrast to `_.map` it returns an object. + function mapObject(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var _keys = keys(obj), + length = _keys.length, + results = {}; + for (var index = 0; index < length; index++) { + var currentKey = _keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + } + + // Predicate-generating function. Often useful outside of Underscore. + function noop(){} + + // Generates a function for a given object that returns a given property. + function propertyOf(obj) { + if (obj == null) return noop; + return function(path) { + return get(obj, path); + }; + } + + // Run a function **n** times. + function times(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + } + + // Return a random integer between `min` and `max` (inclusive). + function random(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + } + + // A (possibly faster) way to get the current timestamp as an integer. + var now = Date.now || function() { + return new Date().getTime(); + }; + + // Internal helper to generate functions for escaping and unescaping strings + // to/from HTML interpolation. + function createEscaper(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped. + var source = '(?:' + keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + } + + // Internal list of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + + // Function for escaping strings to HTML interpolation. + var _escape = createEscaper(escapeMap); + + // Internal list of HTML entities for unescaping. + var unescapeMap = invert(escapeMap); + + // Function for unescaping strings from HTML interpolation. + var _unescape = createEscaper(unescapeMap); + + // By default, Underscore uses ERB-style template delimiters. Change the + // following template settings to use alternative delimiters. + var templateSettings = _$1.templateSettings = { + evaluate: /<%([\s\S]+?)%>/g, + interpolate: /<%=([\s\S]+?)%>/g, + escape: /<%-([\s\S]+?)%>/g + }; + + // When customizing `_.templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g; + + function escapeChar(match) { + return '\\' + escapes[match]; + } + + // In order to prevent third-party code injection through + // `_.templateSettings.variable`, we test it against the following regular + // expression. It is intentionally a bit more liberal than just matching valid + // identifiers, but still prevents possible loopholes through defaults or + // destructuring assignment. + var bareIdentifier = /^\s*(\w|\$)+\s*$/; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + function template(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = defaults({}, settings, _$1.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escapeRegExp, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offset. + return match; + }); + source += "';\n"; + + var argument = settings.variable; + if (argument) { + // Insure against third-party code injection. (CVE-2021-23358) + if (!bareIdentifier.test(argument)) throw new Error( + 'variable is not a bare identifier: ' + argument + ); + } else { + // If a variable is not specified, place data values in local scope. + source = 'with(obj||{}){\n' + source + '}\n'; + argument = 'obj'; + } + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + var render; + try { + render = new Function(argument, '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _$1); + }; + + // Provide the compiled source as a convenience for precompilation. + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + } + + // Traverses the children of `obj` along `path`. If a child is a function, it + // is invoked with its parent as context. Returns the value of the final + // child, or `fallback` if any child is undefined. + function result(obj, path, fallback) { + path = toPath(path); + var length = path.length; + if (!length) { + return isFunction$1(fallback) ? fallback.call(obj) : fallback; + } + for (var i = 0; i < length; i++) { + var prop = obj == null ? void 0 : obj[path[i]]; + if (prop === void 0) { + prop = fallback; + i = length; // Ensure we don't continue iterating. + } + obj = isFunction$1(prop) ? prop.call(obj) : prop; + } + return obj; + } + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + function uniqueId(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + } + + // Start chaining a wrapped Underscore object. + function chain(obj) { + var instance = _$1(obj); + instance._chain = true; + return instance; + } + + // Internal function to execute `sourceFunc` bound to `context` with optional + // `args`. Determines whether to execute a function as a constructor or as a + // normal function. + function executeBound(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (isObject(result)) return result; + return self; + } + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. `_` acts + // as a placeholder by default, allowing any combination of arguments to be + // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument. + var partial = restArguments(function(func, boundArgs) { + var placeholder = partial.placeholder; + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }); + + partial.placeholder = _$1; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). + var bind = restArguments(function(func, context, args) { + if (!isFunction$1(func)) throw new TypeError('Bind must be called on a function'); + var bound = restArguments(function(callArgs) { + return executeBound(func, bound, context, this, args.concat(callArgs)); + }); + return bound; + }); + + // Internal helper for collection methods to determine whether a collection + // should be iterated as an array or as an object. + // Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var isArrayLike = createSizePropertyCheck(getLength); + + // Internal implementation of a recursive `flatten` function. + function flatten$1(input, depth, strict, output) { + output = output || []; + if (!depth && depth !== 0) { + depth = Infinity; + } else if (depth <= 0) { + return output.concat(input); + } + var idx = output.length; + for (var i = 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) { + // Flatten current level of array or arguments object. + if (depth > 1) { + flatten$1(value, depth - 1, strict, output); + idx = output.length; + } else { + var j = 0, len = value.length; + while (j < len) output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + } + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + var bindAll = restArguments(function(obj, keys) { + keys = flatten$1(keys, false, false); + var index = keys.length; + if (index < 1) throw new Error('bindAll must be passed function names'); + while (index--) { + var key = keys[index]; + obj[key] = bind(obj[key], obj); + } + return obj; + }); + + // Memoize an expensive function by storing its results. + function memoize(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!has$1(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + } + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + var delay = restArguments(function(func, wait, args) { + return setTimeout(function() { + return func.apply(null, args); + }, wait); + }); + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + var defer = partial(delay, _$1, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + function throttle(func, wait, options) { + var timeout, context, args, result; + var previous = 0; + if (!options) options = {}; + + var later = function() { + previous = options.leading === false ? 0 : now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + + var throttled = function() { + var _now = now(); + if (!previous && options.leading === false) previous = _now; + var remaining = wait - (_now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = _now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + + throttled.cancel = function() { + clearTimeout(timeout); + previous = 0; + timeout = context = args = null; + }; + + return throttled; + } + + // When a sequence of calls of the returned function ends, the argument + // function is triggered. The end of a sequence is defined by the `wait` + // parameter. If `immediate` is passed, the argument function will be + // triggered at the beginning of the sequence instead of at the end. + function debounce(func, wait, immediate) { + var timeout, previous, args, result, context; + + var later = function() { + var passed = now() - previous; + if (wait > passed) { + timeout = setTimeout(later, wait - passed); + } else { + timeout = null; + if (!immediate) result = func.apply(context, args); + // This check is needed because `func` can recursively invoke `debounced`. + if (!timeout) args = context = null; + } + }; + + var debounced = restArguments(function(_args) { + context = this; + args = _args; + previous = now(); + if (!timeout) { + timeout = setTimeout(later, wait); + if (immediate) result = func.apply(context, args); + } + return result; + }); + + debounced.cancel = function() { + clearTimeout(timeout); + timeout = args = context = null; + }; + + return debounced; + } + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + function wrap(func, wrapper) { + return partial(wrapper, func); + } + + // Returns a negated version of the passed-in predicate. + function negate(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + } + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + function compose() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + } + + // Returns a function that will only be executed on and after the Nth call. + function after(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + } + + // Returns a function that will only be executed up to (but not including) the + // Nth call. + function before(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + } + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + var once = partial(before, 2); + + // Returns the first key on an object that passes a truth test. + function findKey(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = keys(obj), key; + for (var i = 0, length = _keys.length; i < length; i++) { + key = _keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + } + + // Internal function to generate `_.findIndex` and `_.findLastIndex`. + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a truth test. + var findIndex = createPredicateIndexFinder(1); + + // Returns the last index on an array-like that passes a truth test. + var findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + function sortedIndex(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + } + + // Internal function to generate the `_.indexOf` and `_.lastIndexOf` functions. + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), isNaN$1); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + var indexOf = createIndexFinder(1, findIndex, sortedIndex); + + // Return the position of the last occurrence of an item in an array, + // or -1 if the item is not included in the array. + var lastIndexOf = createIndexFinder(-1, findLastIndex); + + // Return the first value which passes a truth test. + function find(obj, predicate, context) { + var keyFinder = isArrayLike(obj) ? findIndex : findKey; + var key = keyFinder(obj, predicate, context); + if (key !== void 0 && key !== -1) return obj[key]; + } + + // Convenience version of a common use case of `_.find`: getting the first + // object containing specific `key:value` pairs. + function findWhere(obj, attrs) { + return find(obj, matcher(attrs)); + } + + // The cornerstone for collection functions, an `each` + // implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + function each(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var _keys = keys(obj); + for (i = 0, length = _keys.length; i < length; i++) { + iteratee(obj[_keys[i]], _keys[i], obj); + } + } + return obj; + } + + // Return the results of applying the iteratee to each element. + function map(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + } + + // Internal helper to create a reducing function, iterating left or right. + function createReduce(dir) { + // Wrap code that reassigns argument variables in a separate function than + // the one that accesses `arguments.length` to avoid a perf hit. (#1991) + var reducer = function(obj, iteratee, memo, initial) { + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length, + index = dir > 0 ? 0 : length - 1; + if (!initial) { + memo = obj[_keys ? _keys[index] : index]; + index += dir; + } + for (; index >= 0 && index < length; index += dir) { + var currentKey = _keys ? _keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + }; + + return function(obj, iteratee, memo, context) { + var initial = arguments.length >= 3; + return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + var reduce = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + var reduceRight = createReduce(-1); + + // Return all the elements that pass a truth test. + function filter(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + } + + // Return all the elements for which a truth test fails. + function reject(obj, predicate, context) { + return filter(obj, negate(cb(predicate)), context); + } + + // Determine whether all of the elements pass a truth test. + function every(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + } + + // Determine if at least one element in the object passes a truth test. + function some(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + } + + // Determine if the array or object contains a given item (using `===`). + function contains(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return indexOf(obj, item, fromIndex) >= 0; + } + + // Invoke a method (with arguments) on every item in a collection. + var invoke = restArguments(function(obj, path, args) { + var contextPath, func; + if (isFunction$1(path)) { + func = path; + } else { + path = toPath(path); + contextPath = path.slice(0, -1); + path = path[path.length - 1]; + } + return map(obj, function(context) { + var method = func; + if (!method) { + if (contextPath && contextPath.length) { + context = deepGet(context, contextPath); + } + if (context == null) return void 0; + method = context[path]; + } + return method == null ? method : method.apply(context, args); + }); + }); + + // Convenience version of a common use case of `_.map`: fetching a property. + function pluck(obj, key) { + return map(obj, property(key)); + } + + // Convenience version of a common use case of `_.filter`: selecting only + // objects containing specific `key:value` pairs. + function where(obj, attrs) { + return filter(obj, matcher(attrs)); + } + + // Return the maximum element (or element-based computation). + function max(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) { + obj = isArrayLike(obj) ? obj : values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value != null && value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + each(obj, function(v, index, list) { + computed = iteratee(v, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = v; + lastComputed = computed; + } + }); + } + return result; + } + + // Return the minimum element (or element-based computation). + function min(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) { + obj = isArrayLike(obj) ? obj : values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value != null && value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + each(obj, function(v, index, list) { + computed = iteratee(v, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = v; + lastComputed = computed; + } + }); + } + return result; + } + + // Sample **n** random values from a collection using the modern version of the + // [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `_.map`. + function sample(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = values(obj); + return obj[random(obj.length - 1)]; + } + var sample = isArrayLike(obj) ? clone(obj) : values(obj); + var length = getLength(sample); + n = Math.max(Math.min(n, length), 0); + var last = length - 1; + for (var index = 0; index < n; index++) { + var rand = random(index, last); + var temp = sample[index]; + sample[index] = sample[rand]; + sample[rand] = temp; + } + return sample.slice(0, n); + } + + // Shuffle a collection. + function shuffle(obj) { + return sample(obj, Infinity); + } + + // Sort the object's values by a criterion produced by an iteratee. + function sortBy(obj, iteratee, context) { + var index = 0; + iteratee = cb(iteratee, context); + return pluck(map(obj, function(value, key, list) { + return { + value: value, + index: index++, + criteria: iteratee(value, key, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + } + + // An internal function used for aggregate "group by" operations. + function group(behavior, partition) { + return function(obj, iteratee, context) { + var result = partition ? [[], []] : {}; + iteratee = cb(iteratee, context); + each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + } + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + var groupBy = group(function(result, value, key) { + if (has$1(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `_.groupBy`, but for + // when you know that your index values will be unique. + var indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + var countBy = group(function(result, value, key) { + if (has$1(result, key)) result[key]++; else result[key] = 1; + }); + + // Split a collection into two arrays: one whose elements all pass the given + // truth test, and one whose elements all do not pass the truth test. + var partition = group(function(result, value, pass) { + result[pass ? 0 : 1].push(value); + }, true); + + // Safely create a real, live array from anything iterable. + var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g; + function toArray(obj) { + if (!obj) return []; + if (isArray(obj)) return slice.call(obj); + if (isString(obj)) { + // Keep surrogate pair characters together. + return obj.match(reStrSymbol); + } + if (isArrayLike(obj)) return map(obj, identity); + return values(obj); + } + + // Return the number of elements in a collection. + function size(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : keys(obj).length; + } + + // Internal `_.pick` helper function to determine whether `key` is an enumerable + // property name of `obj`. + function keyInObj(value, key, obj) { + return key in obj; + } + + // Return a copy of the object only containing the allowed properties. + var pick = restArguments(function(obj, keys) { + var result = {}, iteratee = keys[0]; + if (obj == null) return result; + if (isFunction$1(iteratee)) { + if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]); + keys = allKeys(obj); + } else { + iteratee = keyInObj; + keys = flatten$1(keys, false, false); + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }); + + // Return a copy of the object without the disallowed properties. + var omit = restArguments(function(obj, keys) { + var iteratee = keys[0], context; + if (isFunction$1(iteratee)) { + iteratee = negate(iteratee); + if (keys.length > 1) context = keys[1]; + } else { + keys = map(flatten$1(keys, false, false), String); + iteratee = function(value, key) { + return !contains(keys, key); + }; + } + return pick(obj, iteratee, context); + }); + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + function initial(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + } + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. The **guard** check allows it to work with `_.map`. + function first(array, n, guard) { + if (array == null || array.length < 1) return n == null || guard ? void 0 : []; + if (n == null || guard) return array[0]; + return initial(array, array.length - n); + } + + // Returns everything but the first entry of the `array`. Especially useful on + // the `arguments` object. Passing an **n** will return the rest N values in the + // `array`. + function rest(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + } + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + function last(array, n, guard) { + if (array == null || array.length < 1) return n == null || guard ? void 0 : []; + if (n == null || guard) return array[array.length - 1]; + return rest(array, Math.max(0, array.length - n)); + } + + // Trim out all falsy values from an array. + function compact(array) { + return filter(array, Boolean); + } + + // Flatten out an array, either recursively (by default), or up to `depth`. + // Passing `true` or `false` as `depth` means `1` or `Infinity`, respectively. + function flatten(array, depth) { + return flatten$1(array, depth, false); + } + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + var difference = restArguments(function(array, rest) { + rest = flatten$1(rest, true, true); + return filter(array, function(value){ + return !contains(rest, value); + }); + }); + + // Return a version of the array that does not contain the specified value(s). + var without = restArguments(function(array, otherArrays) { + return difference(array, otherArrays); + }); + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // The faster algorithm will not work with an iteratee if the iteratee + // is not a one-to-one function, so providing an iteratee will disable + // the faster algorithm. + function uniq(array, isSorted, iteratee, context) { + if (!isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted && !iteratee) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!contains(result, value)) { + result.push(value); + } + } + return result; + } + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + var union = restArguments(function(arrays) { + return uniq(flatten$1(arrays, true, true)); + }); + + // Produce an array that contains every item shared between all the + // passed-in arrays. + function intersection(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (contains(result, item)) continue; + var j; + for (j = 1; j < argsLength; j++) { + if (!contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + } + + // Complement of zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices. + function unzip(array) { + var length = array && max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = pluck(array, index); + } + return result; + } + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + var zip = restArguments(unzip); + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. Passing by pairs is the reverse of `_.pairs`. + function object(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + } + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](https://docs.python.org/library/functions.html#range). + function range(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + if (!step) { + step = stop < start ? -1 : 1; + } + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + } + + // Chunk a single array into multiple arrays, each containing `count` or fewer + // items. + function chunk(array, count) { + if (count == null || count < 1) return []; + var result = []; + var i = 0, length = array.length; + while (i < length) { + result.push(slice.call(array, i, i += count)); + } + return result; + } + + // Helper function to continue chaining intermediate results. + function chainResult(instance, obj) { + return instance._chain ? _$1(obj).chain() : obj; + } + + // Add your own custom functions to the Underscore object. + function mixin(obj) { + each(functions(obj), function(name) { + var func = _$1[name] = obj[name]; + _$1.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return chainResult(this, func.apply(_$1, args)); + }; + }); + return _$1; + } + + // Add all mutator `Array` functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _$1.prototype[name] = function() { + var obj = this._wrapped; + if (obj != null) { + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) { + delete obj[0]; + } + } + return chainResult(this, obj); + }; + }); + + // Add all accessor `Array` functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _$1.prototype[name] = function() { + var obj = this._wrapped; + if (obj != null) obj = method.apply(obj, arguments); + return chainResult(this, obj); + }; + }); + + // Named Exports + + var allExports = { + __proto__: null, + VERSION: VERSION, + restArguments: restArguments, + isObject: isObject, + isNull: isNull, + isUndefined: isUndefined, + isBoolean: isBoolean, + isElement: isElement, + isString: isString, + isNumber: isNumber, + isDate: isDate, + isRegExp: isRegExp, + isError: isError, + isSymbol: isSymbol, + isArrayBuffer: isArrayBuffer, + isDataView: isDataView$1, + isArray: isArray, + isFunction: isFunction$1, + isArguments: isArguments$1, + isFinite: isFinite$1, + isNaN: isNaN$1, + isTypedArray: isTypedArray$1, + isEmpty: isEmpty, + isMatch: isMatch, + isEqual: isEqual, + isMap: isMap, + isWeakMap: isWeakMap, + isSet: isSet, + isWeakSet: isWeakSet, + keys: keys, + allKeys: allKeys, + values: values, + pairs: pairs, + invert: invert, + functions: functions, + methods: functions, + extend: extend, + extendOwn: extendOwn, + assign: extendOwn, + defaults: defaults, + create: create, + clone: clone, + tap: tap, + get: get, + has: has, + mapObject: mapObject, + identity: identity, + constant: constant, + noop: noop, + toPath: toPath$1, + property: property, + propertyOf: propertyOf, + matcher: matcher, + matches: matcher, + times: times, + random: random, + now: now, + escape: _escape, + unescape: _unescape, + templateSettings: templateSettings, + template: template, + result: result, + uniqueId: uniqueId, + chain: chain, + iteratee: iteratee, + partial: partial, + bind: bind, + bindAll: bindAll, + memoize: memoize, + delay: delay, + defer: defer, + throttle: throttle, + debounce: debounce, + wrap: wrap, + negate: negate, + compose: compose, + after: after, + before: before, + once: once, + findKey: findKey, + findIndex: findIndex, + findLastIndex: findLastIndex, + sortedIndex: sortedIndex, + indexOf: indexOf, + lastIndexOf: lastIndexOf, + find: find, + detect: find, + findWhere: findWhere, + each: each, + forEach: each, + map: map, + collect: map, + reduce: reduce, + foldl: reduce, + inject: reduce, + reduceRight: reduceRight, + foldr: reduceRight, + filter: filter, + select: filter, + reject: reject, + every: every, + all: every, + some: some, + any: some, + contains: contains, + includes: contains, + include: contains, + invoke: invoke, + pluck: pluck, + where: where, + max: max, + min: min, + shuffle: shuffle, + sample: sample, + sortBy: sortBy, + groupBy: groupBy, + indexBy: indexBy, + countBy: countBy, + partition: partition, + toArray: toArray, + size: size, + pick: pick, + omit: omit, + first: first, + head: first, + take: first, + initial: initial, + last: last, + rest: rest, + tail: rest, + drop: rest, + compact: compact, + flatten: flatten, + without: without, + uniq: uniq, + unique: uniq, + union: union, + intersection: intersection, + difference: difference, + unzip: unzip, + transpose: unzip, + zip: zip, + object: object, + range: range, + chunk: chunk, + mixin: mixin, + 'default': _$1 + }; + + // Default Export + + // Add all of the Underscore functions to the wrapper object. + var _ = mixin(allExports); + // Legacy Node.js API. + _._ = _; + + return _; + +}))); +//# sourceMappingURL=underscore-umd.js.map diff --git a/_static/underscore.js b/_static/underscore.js new file mode 100644 index 00000000000..cf177d4285a --- /dev/null +++ b/_static/underscore.js @@ -0,0 +1,6 @@ +!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("underscore",r):(n="undefined"!=typeof globalThis?globalThis:n||self,function(){var t=n._,e=n._=r();e.noConflict=function(){return n._=t,e}}())}(this,(function(){ +// Underscore.js 1.13.1 +// https://underscorejs.org +// (c) 2009-2021 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. +var n="1.13.1",r="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},t=Array.prototype,e=Object.prototype,u="undefined"!=typeof Symbol?Symbol.prototype:null,o=t.push,i=t.slice,a=e.toString,f=e.hasOwnProperty,c="undefined"!=typeof ArrayBuffer,l="undefined"!=typeof DataView,s=Array.isArray,p=Object.keys,v=Object.create,h=c&&ArrayBuffer.isView,y=isNaN,d=isFinite,g=!{toString:null}.propertyIsEnumerable("toString"),b=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],m=Math.pow(2,53)-1;function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math.max(arguments.length-r,0),e=Array(t),u=0;u<t;u++)e[u]=arguments[u+r];switch(r){case 0:return n.call(this,e);case 1:return n.call(this,arguments[0],e);case 2:return n.call(this,arguments[0],arguments[1],e)}var o=Array(r+1);for(u=0;u<r;u++)o[u]=arguments[u];return o[r]=e,n.apply(this,o)}}function _(n){var r=typeof n;return"function"===r||"object"===r&&!!n}function w(n){return void 0===n}function A(n){return!0===n||!1===n||"[object Boolean]"===a.call(n)}function x(n){var r="[object "+n+"]";return function(n){return a.call(n)===r}}var S=x("String"),O=x("Number"),M=x("Date"),E=x("RegExp"),B=x("Error"),N=x("Symbol"),I=x("ArrayBuffer"),T=x("Function"),k=r.document&&r.document.childNodes;"function"!=typeof/./&&"object"!=typeof Int8Array&&"function"!=typeof k&&(T=function(n){return"function"==typeof n||!1});var D=T,R=x("Object"),F=l&&R(new DataView(new ArrayBuffer(8))),V="undefined"!=typeof Map&&R(new Map),P=x("DataView");var q=F?function(n){return null!=n&&D(n.getInt8)&&I(n.buffer)}:P,U=s||x("Array");function W(n,r){return null!=n&&f.call(n,r)}var z=x("Arguments");!function(){z(arguments)||(z=function(n){return W(n,"callee")})}();var L=z;function $(n){return O(n)&&y(n)}function C(n){return function(){return n}}function K(n){return function(r){var t=n(r);return"number"==typeof t&&t>=0&&t<=m}}function J(n){return function(r){return null==r?void 0:r[n]}}var G=J("byteLength"),H=K(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:C(!1),Y=J("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e<t;++e)r[n[e]]=!0;return{contains:function(n){return r[n]},push:function(t){return r[t]=!0,n.push(t)}}}(r);var t=b.length,u=n.constructor,o=D(u)&&u.prototype||e,i="constructor";for(W(n,i)&&!r.contains(i)&&r.push(i);t--;)(i=b[t])in n&&n[i]!==o[i]&&!r.contains(i)&&r.push(i)}function nn(n){if(!_(n))return[];if(p)return p(n);var r=[];for(var t in n)W(n,t)&&r.push(t);return g&&Z(n,r),r}function rn(n,r){var t=nn(r),e=t.length;if(null==n)return!e;for(var u=Object(n),o=0;o<e;o++){var i=t[o];if(r[i]!==u[i]||!(i in u))return!1}return!0}function tn(n){return n instanceof tn?n:this instanceof tn?void(this._wrapped=n):new tn(n)}function en(n){return new Uint8Array(n.buffer||n,n.byteOffset||0,G(n))}tn.VERSION=n,tn.prototype.value=function(){return this._wrapped},tn.prototype.valueOf=tn.prototype.toJSON=tn.prototype.value,tn.prototype.toString=function(){return String(this._wrapped)};var un="[object DataView]";function on(n,r,t,e){if(n===r)return 0!==n||1/n==1/r;if(null==n||null==r)return!1;if(n!=n)return r!=r;var o=typeof n;return("function"===o||"object"===o||"object"==typeof r)&&function n(r,t,e,o){r instanceof tn&&(r=r._wrapped);t instanceof tn&&(t=t._wrapped);var i=a.call(r);if(i!==a.call(t))return!1;if(F&&"[object Object]"==i&&q(r)){if(!q(t))return!1;i=un}switch(i){case"[object RegExp]":case"[object String]":return""+r==""+t;case"[object Number]":return+r!=+r?+t!=+t:0==+r?1/+r==1/t:+r==+t;case"[object Date]":case"[object Boolean]":return+r==+t;case"[object Symbol]":return u.valueOf.call(r)===u.valueOf.call(t);case"[object ArrayBuffer]":case un:return n(en(r),en(t),e,o)}var f="[object Array]"===i;if(!f&&X(r)){if(G(r)!==G(t))return!1;if(r.buffer===t.buffer&&r.byteOffset===t.byteOffset)return!0;f=!0}if(!f){if("object"!=typeof r||"object"!=typeof t)return!1;var c=r.constructor,l=t.constructor;if(c!==l&&!(D(c)&&c instanceof c&&D(l)&&l instanceof l)&&"constructor"in r&&"constructor"in t)return!1}o=o||[];var s=(e=e||[]).length;for(;s--;)if(e[s]===r)return o[s]===t;if(e.push(r),o.push(t),f){if((s=r.length)!==t.length)return!1;for(;s--;)if(!on(r[s],t[s],e,o))return!1}else{var p,v=nn(r);if(s=v.length,nn(t).length!==s)return!1;for(;s--;)if(p=v[s],!W(t,p)||!on(r[p],t[p],e,o))return!1}return e.pop(),o.pop(),!0}(n,r,t,e)}function an(n){if(!_(n))return[];var r=[];for(var t in n)r.push(t);return g&&Z(n,r),r}function fn(n){var r=Y(n);return function(t){if(null==t)return!1;var e=an(t);if(Y(e))return!1;for(var u=0;u<r;u++)if(!D(t[n[u]]))return!1;return n!==hn||!D(t[cn])}}var cn="forEach",ln="has",sn=["clear","delete"],pn=["get",ln,"set"],vn=sn.concat(cn,pn),hn=sn.concat(pn),yn=["add"].concat(sn,cn,ln),dn=V?fn(vn):x("Map"),gn=V?fn(hn):x("WeakMap"),bn=V?fn(yn):x("Set"),mn=x("WeakSet");function jn(n){for(var r=nn(n),t=r.length,e=Array(t),u=0;u<t;u++)e[u]=n[r[u]];return e}function _n(n){for(var r={},t=nn(n),e=0,u=t.length;e<u;e++)r[n[t[e]]]=t[e];return r}function wn(n){var r=[];for(var t in n)D(n[t])&&r.push(t);return r.sort()}function An(n,r){return function(t){var e=arguments.length;if(r&&(t=Object(t)),e<2||null==t)return t;for(var u=1;u<e;u++)for(var o=arguments[u],i=n(o),a=i.length,f=0;f<a;f++){var c=i[f];r&&void 0!==t[c]||(t[c]=o[c])}return t}}var xn=An(an),Sn=An(nn),On=An(an,!0);function Mn(n){if(!_(n))return{};if(v)return v(n);var r=function(){};r.prototype=n;var t=new r;return r.prototype=null,t}function En(n){return _(n)?U(n)?n.slice():xn({},n):n}function Bn(n){return U(n)?n:[n]}function Nn(n){return tn.toPath(n)}function In(n,r){for(var t=r.length,e=0;e<t;e++){if(null==n)return;n=n[r[e]]}return t?n:void 0}function Tn(n,r,t){var e=In(n,Nn(r));return w(e)?t:e}function kn(n){return n}function Dn(n){return n=Sn({},n),function(r){return rn(r,n)}}function Rn(n){return n=Nn(n),function(r){return In(r,n)}}function Fn(n,r,t){if(void 0===r)return n;switch(null==t?3:t){case 1:return function(t){return n.call(r,t)};case 3:return function(t,e,u){return n.call(r,t,e,u)};case 4:return function(t,e,u,o){return n.call(r,t,e,u,o)}}return function(){return n.apply(r,arguments)}}function Vn(n,r,t){return null==n?kn:D(n)?Fn(n,r,t):_(n)&&!U(n)?Dn(n):Rn(n)}function Pn(n,r){return Vn(n,r,1/0)}function qn(n,r,t){return tn.iteratee!==Pn?tn.iteratee(n,r):Vn(n,r,t)}function Un(){}function Wn(n,r){return null==r&&(r=n,n=0),n+Math.floor(Math.random()*(r-n+1))}tn.toPath=Bn,tn.iteratee=Pn;var zn=Date.now||function(){return(new Date).getTime()};function Ln(n){var r=function(r){return n[r]},t="(?:"+nn(n).join("|")+")",e=RegExp(t),u=RegExp(t,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,r):n}}var $n={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Cn=Ln($n),Kn=Ln(_n($n)),Jn=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=/^\s*(\w|\$)+\s*$/;var Zn=0;function nr(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var rr=j((function(n,r){var t=rr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a<o;a++)i[a]=r[a]===t?arguments[u++]:r[a];for(;u<arguments.length;)i.push(arguments[u++]);return nr(n,e,this,this,i)};return e}));rr.placeholder=tn;var tr=j((function(n,r,t){if(!D(n))throw new TypeError("Bind must be called on a function");var e=j((function(u){return nr(n,e,r,this,t.concat(u))}));return e})),er=K(Y);function ur(n,r,t,e){if(e=e||[],r||0===r){if(r<=0)return e.concat(n)}else r=1/0;for(var u=e.length,o=0,i=Y(n);o<i;o++){var a=n[o];if(er(a)&&(U(a)||L(a)))if(r>1)ur(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f<c;)e[u++]=a[f++];else t||(e[u++]=a)}return e}var or=j((function(n,r){var t=(r=ur(r,!1,!1)).length;if(t<1)throw new Error("bindAll must be passed function names");for(;t--;){var e=r[t];n[e]=tr(n[e],n)}return n}));var ir=j((function(n,r,t){return setTimeout((function(){return n.apply(null,t)}),r)})),ar=rr(ir,tn,1);function fr(n){return function(){return!n.apply(this,arguments)}}function cr(n,r){var t;return function(){return--n>0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var lr=rr(cr,2);function sr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o<i;o++)if(r(n[e=u[o]],e,n))return e}function pr(n){return function(r,t,e){t=qn(t,e);for(var u=Y(r),o=n>0?0:u-1;o>=0&&o<u;o+=n)if(t(r[o],o,r))return o;return-1}}var vr=pr(1),hr=pr(-1);function yr(n,r,t,e){for(var u=(t=qn(t,e,1))(r),o=0,i=Y(n);o<i;){var a=Math.floor((o+i)/2);t(n[a])<u?o=a+1:i=a}return o}function dr(n,r,t){return function(e,u,o){var a=0,f=Y(e);if("number"==typeof o)n>0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),$))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o<f;o+=n)if(e[o]===u)return o;return-1}}var gr=dr(1,vr,yr),br=dr(-1,hr);function mr(n,r,t){var e=(er(n)?vr:sr)(n,r,t);if(void 0!==e&&-1!==e)return n[e]}function jr(n,r,t){var e,u;if(r=Fn(r,t),er(n))for(e=0,u=n.length;e<u;e++)r(n[e],e,n);else{var o=nn(n);for(e=0,u=o.length;e<u;e++)r(n[o[e]],o[e],n)}return n}function _r(n,r,t){r=qn(r,t);for(var e=!er(n)&&nn(n),u=(e||n).length,o=Array(u),i=0;i<u;i++){var a=e?e[i]:i;o[i]=r(n[a],a,n)}return o}function wr(n){var r=function(r,t,e,u){var o=!er(r)&&nn(r),i=(o||r).length,a=n>0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a<i;a+=n){var f=o?o[a]:a;e=t(e,r[f],f,r)}return e};return function(n,t,e,u){var o=arguments.length>=3;return r(n,Fn(t,u,4),e,o)}}var Ar=wr(1),xr=wr(-1);function Sr(n,r,t){var e=[];return r=qn(r,t),jr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Or(n,r,t){r=qn(r,t);for(var e=!er(n)&&nn(n),u=(e||n).length,o=0;o<u;o++){var i=e?e[o]:o;if(!r(n[i],i,n))return!1}return!0}function Mr(n,r,t){r=qn(r,t);for(var e=!er(n)&&nn(n),u=(e||n).length,o=0;o<u;o++){var i=e?e[o]:o;if(r(n[i],i,n))return!0}return!1}function Er(n,r,t,e){return er(n)||(n=jn(n)),("number"!=typeof t||e)&&(t=0),gr(n,r,t)>=0}var Br=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),_r(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Nr(n,r){return _r(n,Rn(r))}function Ir(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;a<f;a++)null!=(e=n[a])&&e>o&&(o=e);else r=qn(r,t),jr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Tr(n,r,t){if(null==r||t)return er(n)||(n=jn(n)),n[Wn(n.length-1)];var e=er(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i<r;i++){var a=Wn(i,o),f=e[i];e[i]=e[a],e[a]=f}return e.slice(0,r)}function kr(n,r){return function(t,e,u){var o=r?[[],[]]:{};return e=qn(e,u),jr(t,(function(r,u){var i=e(r,u,t);n(o,r,i)})),o}}var Dr=kr((function(n,r,t){W(n,t)?n[t].push(r):n[t]=[r]})),Rr=kr((function(n,r,t){n[t]=r})),Fr=kr((function(n,r,t){W(n,t)?n[t]++:n[t]=1})),Vr=kr((function(n,r,t){n[t?0:1].push(r)}),!0),Pr=/[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;function qr(n,r,t){return r in t}var Ur=j((function(n,r){var t={},e=r[0];if(null==n)return t;D(e)?(r.length>1&&(e=Fn(e,r[1])),r=an(n)):(e=qr,r=ur(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u<o;u++){var i=r[u],a=n[i];e(a,i,n)&&(t[i]=a)}return t})),Wr=j((function(n,r){var t,e=r[0];return D(e)?(e=fr(e),r.length>1&&(t=r[1])):(r=_r(ur(r,!1,!1),String),e=function(n,t){return!Er(r,t)}),Ur(n,e,t)}));function zr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function Lr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:zr(n,n.length-r)}function $r(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=ur(r,!0,!0),Sr(n,(function(n){return!Er(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);i<a;i++){var f=n[i],c=t?t(f,i,n):f;r&&!t?(i&&o===c||u.push(f),o=c):t?Er(o,c)||(o.push(c),u.push(f)):Er(u,f)||u.push(f)}return u}var Gr=j((function(n){return Jr(ur(n,!0,!0))}));function Hr(n){for(var r=n&&Ir(n,Y).length||0,t=Array(r),e=0;e<r;e++)t[e]=Nr(n,e);return t}var Qr=j(Hr);function Xr(n,r){return n._chain?tn(r).chain():r}function Yr(n){return jr(wn(n),(function(r){var t=tn[r]=n[r];tn.prototype[r]=function(){var n=[this._wrapped];return o.apply(n,arguments),Xr(this,t.apply(tn,n))}})),tn}jr(["pop","push","reverse","shift","sort","splice","unshift"],(function(n){var r=t[n];tn.prototype[n]=function(){var t=this._wrapped;return null!=t&&(r.apply(t,arguments),"shift"!==n&&"splice"!==n||0!==t.length||delete t[0]),Xr(this,t)}})),jr(["concat","join","slice"],(function(n){var r=t[n];tn.prototype[n]=function(){var n=this._wrapped;return null!=n&&(n=r.apply(n,arguments)),Xr(this,n)}}));var Zr=Yr({__proto__:null,VERSION:n,restArguments:j,isObject:_,isNull:function(n){return null===n},isUndefined:w,isBoolean:A,isElement:function(n){return!(!n||1!==n.nodeType)},isString:S,isNumber:O,isDate:M,isRegExp:E,isError:B,isSymbol:N,isArrayBuffer:I,isDataView:q,isArray:U,isFunction:D,isArguments:L,isFinite:function(n){return!N(n)&&d(n)&&!isNaN(parseFloat(n))},isNaN:$,isTypedArray:X,isEmpty:function(n){if(null==n)return!0;var r=Y(n);return"number"==typeof r&&(U(n)||S(n)||L(n))?0===r:0===Y(nn(n))},isMatch:rn,isEqual:function(n,r){return on(n,r)},isMap:dn,isWeakMap:gn,isSet:bn,isWeakSet:mn,keys:nn,allKeys:an,values:jn,pairs:function(n){for(var r=nn(n),t=r.length,e=Array(t),u=0;u<t;u++)e[u]=[r[u],n[r[u]]];return e},invert:_n,functions:wn,methods:wn,extend:xn,extendOwn:Sn,assign:Sn,defaults:On,create:function(n,r){var t=Mn(n);return r&&Sn(t,r),t},clone:En,tap:function(n,r){return r(n),n},get:Tn,has:function(n,r){for(var t=(r=Nn(r)).length,e=0;e<t;e++){var u=r[e];if(!W(n,u))return!1;n=n[u]}return!!t},mapObject:function(n,r,t){r=qn(r,t);for(var e=nn(n),u=e.length,o={},i=0;i<u;i++){var a=e[i];o[a]=r(n[a],a,n)}return o},identity:kn,constant:C,noop:Un,toPath:Bn,property:Rn,propertyOf:function(n){return null==n?Un:function(r){return Tn(n,r)}},matcher:Dn,matches:Dn,times:function(n,r,t){var e=Array(Math.max(0,n));r=Fn(r,t,1);for(var u=0;u<n;u++)e[u]=r(u);return e},random:Wn,now:zn,escape:Cn,unescape:Kn,templateSettings:Jn,template:function(n,r,t){!r&&t&&(r=t),r=On({},r,tn.templateSettings);var e=RegExp([(r.escape||Gn).source,(r.interpolate||Gn).source,(r.evaluate||Gn).source].join("|")+"|$","g"),u=0,o="__p+='";n.replace(e,(function(r,t,e,i,a){return o+=n.slice(u,a).replace(Qn,Xn),u=a+r.length,t?o+="'+\n((__t=("+t+"))==null?'':_.escape(__t))+\n'":e?o+="'+\n((__t=("+e+"))==null?'':__t)+\n'":i&&(o+="';\n"+i+"\n__p+='"),r})),o+="';\n";var i,a=r.variable;if(a){if(!Yn.test(a))throw new Error("variable is not a bare identifier: "+a)}else o="with(obj||{}){\n"+o+"}\n",a="obj";o="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{i=new Function(a,"_",o)}catch(n){throw n.source=o,n}var f=function(n){return i.call(this,n,tn)};return f.source="function("+a+"){\n"+o+"}",f},result:function(n,r,t){var e=(r=Nn(r)).length;if(!e)return D(t)?t.call(n):t;for(var u=0;u<e;u++){var o=null==n?void 0:n[r[u]];void 0===o&&(o=t,u=e),n=D(o)?o.call(n):o}return n},uniqueId:function(n){var r=++Zn+"";return n?n+r:r},chain:function(n){var r=tn(n);return r._chain=!0,r},iteratee:Pn,partial:rr,bind:tr,bindAll:or,memoize:function(n,r){var t=function(e){var u=t.cache,o=""+(r?r.apply(this,arguments):e);return W(u,o)||(u[o]=n.apply(this,arguments)),u[o]};return t.cache={},t},delay:ir,defer:ar,throttle:function(n,r,t){var e,u,o,i,a=0;t||(t={});var f=function(){a=!1===t.leading?0:zn(),e=null,i=n.apply(u,o),e||(u=o=null)},c=function(){var c=zn();a||!1!==t.leading||(a=c);var l=r-(c-a);return u=this,o=arguments,l<=0||l>r?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o,i,a,f=function(){var c=zn()-u;r>c?e=setTimeout(f,r-c):(e=null,t||(i=n.apply(a,o)),e||(o=a=null))},c=j((function(c){return a=this,o=c,u=zn(),e||(e=setTimeout(f,r),t&&(i=n.apply(a,o))),i}));return c.cancel=function(){clearTimeout(e),e=o=a=null},c},wrap:function(n,r){return rr(r,n)},negate:fr,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:cr,once:lr,findKey:sr,findIndex:vr,findLastIndex:hr,sortedIndex:yr,indexOf:gr,lastIndexOf:br,find:mr,detect:mr,findWhere:function(n,r){return mr(n,Dn(r))},each:jr,forEach:jr,map:_r,collect:_r,reduce:Ar,foldl:Ar,inject:Ar,reduceRight:xr,foldr:xr,filter:Sr,select:Sr,reject:function(n,r,t){return Sr(n,fr(qn(r)),t)},every:Or,all:Or,some:Mr,any:Mr,contains:Er,includes:Er,include:Er,invoke:Br,pluck:Nr,where:function(n,r){return Sr(n,Dn(r))},max:Ir,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;a<f;a++)null!=(e=n[a])&&e<o&&(o=e);else r=qn(r,t),jr(n,(function(n,t,e){((u=r(n,t,e))<i||u===1/0&&o===1/0)&&(o=n,i=u)}));return o},shuffle:function(n){return Tr(n,1/0)},sample:Tr,sortBy:function(n,r,t){var e=0;return r=qn(r,t),Nr(_r(n,(function(n,t,u){return{value:n,index:e++,criteria:r(n,t,u)}})).sort((function(n,r){var t=n.criteria,e=r.criteria;if(t!==e){if(t>e||void 0===t)return 1;if(t<e||void 0===e)return-1}return n.index-r.index})),"value")},groupBy:Dr,indexBy:Rr,countBy:Fr,partition:Vr,toArray:function(n){return n?U(n)?i.call(n):S(n)?n.match(Pr):er(n)?_r(n,kn):jn(n):[]},size:function(n){return null==n?0:er(n)?n.length:nn(n).length},pick:Ur,omit:Wr,first:Lr,head:Lr,take:Lr,initial:zr,last:function(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[n.length-1]:$r(n,Math.max(0,n.length-r))},rest:$r,tail:$r,drop:$r,compact:function(n){return Sr(n,Boolean)},flatten:function(n,r){return ur(n,r,!1)},without:Kr,uniq:Jr,unique:Jr,union:Gr,intersection:function(n){for(var r=[],t=arguments.length,e=0,u=Y(n);e<u;e++){var o=n[e];if(!Er(r,o)){var i;for(i=1;i<t&&Er(arguments[i],o);i++);i===t&&r.push(o)}}return r},difference:Cr,unzip:Hr,transpose:Hr,zip:Qr,object:function(n,r){for(var t={},e=0,u=Y(n);e<u;e++)r?t[n[e]]=r[e]:t[n[e][0]]=n[e][1];return t},range:function(n,r,t){null==r&&(r=n||0,n=0),t||(t=r<n?-1:1);for(var e=Math.max(Math.ceil((r-n)/t),0),u=Array(e),o=0;o<e;o++,n+=t)u[o]=n;return u},chunk:function(n,r){if(null==r||r<1)return[];for(var t=[],e=0,u=n.length;e<u;)t.push(i.call(n,e,e+=r));return t},mixin:Yr,default:tn});return Zr._=Zr,Zr})); \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 05ad8a2820c..00000000000 --- a/appveyor.yml +++ /dev/null @@ -1,50 +0,0 @@ -os: Visual Studio 2022 - -environment: - global: - # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the - # /E:ON and /V:ON options are not enabled in the batch script intepreter - # See: https://stackoverflow.com/a/13751649/163740 - CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd" - - matrix: - - PYTHON_DIR: C:\Python310-x64 - -branches: - only: - - master - -init: - - "ECHO %PYTHON_DIR%" - -install: - # If there is a newer build queued for the same PR, cancel this one. - # The AppVeyor 'rollout builds' option is supposed to serve the same - # purpose but it is problematic because it tends to cancel builds pushed - # directly to master instead of just PR builds (or the converse). - # credits: JuliaLang developers. - - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` - https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` - Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` - throw "There are newer queued builds for this pull request, failing early." } - - ECHO "Filesystem root:" - - ps: "ls \"C:/\"" - - # Prepend newly installed Python to the PATH of this build (this cannot be - # done from inside the powershell script as it would require to restart - # the parent CMD process). - - SET PATH=%PYTHON_DIR%;%PYTHON_DIR%\\Scripts;%PATH% - - SET PATH=%PYTHON%;%PYTHON%\Scripts;%PYTHON%\Library\bin;%PATH% - - SET PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin - - "python -m pip install --upgrade pip" - - "python -m pip install -r requirements/requirements.txt" - - "python -m pip install pytest-xdist" - - # Check that we have the expected version and architecture for Python - - "python --version" - - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - -build: off - -test_script: - - "pytest tests -n auto -Werror --durations=0" diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index ae495eb36d2..00000000000 --- a/docs/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -# SPHINXOPTS with -W means turn warnings into errors to fail the build when warnings are present. -SPHINXOPTS = -W -SPHINXBUILD = sphinx-build -SPHINXPROJ = PythonRobotics -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index fb7d4cc3bc7..00000000000 --- a/docs/README.md +++ /dev/null @@ -1,29 +0,0 @@ -## Python Robotics Documentation - -This folder contains documentation for the Python Robotics project. - - -### Build the Documentation - -#### Install Sphinx and Theme - -``` -pip install sphinx sphinx-autobuild sphinx-rtd-theme sphinx_rtd_dark_mode sphinx_copybutton sphinx_rtd_dark_mode -``` - -#### Building the Docs - -In the `docs/` folder: -``` -make html -``` - -if you want to building each time a file is changed: - -``` -sphinx-autobuild . _build/html -``` - -#### Check the generated doc - -Open the index.html file under docs/_build/ diff --git a/docs/_static/.gitkeep b/docs/_static/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html deleted file mode 100644 index 4b5b2789323..00000000000 --- a/docs/_templates/layout.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "!layout.html" %} - -{% block sidebartitle %} -{{ super() }} -<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" - crossorigin="anonymous"></script> -<!-- PythonRoboticsDoc --> -<ins class="adsbygoogle" - style="display:block" - data-ad-client="ca-pub-9612347954373886" - data-ad-slot="1579532132" - data-ad-format="auto" - data-full-width-responsive="true"></ins> -<script> - (adsbygoogle = window.adsbygoogle || []).push({}); -</script> -{% endblock %} diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index eeabab11b1c..00000000000 --- a/docs/conf.py +++ /dev/null @@ -1,230 +0,0 @@ -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# https://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -from pathlib import Path - -sys.path.insert(0, os.path.abspath('../')) - - -# -- Project information ----------------------------------------------------- - -project = 'PythonRobotics' -copyright = '2018-now, Atsushi Sakai' -author = 'Atsushi Sakai' - -# The short X.Y version -version = '' -# The full version, including alpha/beta/rc tags -release = '' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'matplotlib.sphinxext.plot_directive', - 'sphinx.ext.autodoc', - 'sphinx.ext.mathjax', - 'sphinx.ext.linkcode', - 'sphinx.ext.napoleon', - 'sphinx.ext.imgconverter', - 'IPython.sphinxext.ipython_console_highlighting', - 'sphinx_copybutton', - 'sphinx_rtd_dark_mode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '_main.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = "en" - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path . -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -# Fix for read the docs -on_rtd = os.environ.get('READTHEDOCS') == 'True' -if on_rtd: - html_theme = 'default' -else: - html_theme = 'sphinx_rtd_light_them' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -html_logo = '../icon.png' -html_theme_options = { - 'display_version': False, -} - -# replace "view page source" with "edit on github" in Read The Docs theme -# * https://github.com/readthedocs/sphinx_rtd_theme/issues/529 -html_context = { - 'display_github': True, - 'github_user': 'AtsushiSakai', - 'github_repo': 'PythonRobotics', - 'github_version': 'master', - "conf_py_path": "/docs/", - "source_suffix": source_suffix, -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -html_css_files = ['custom.css'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PythonRoboticsdoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'PythonRobotics.tex', 'PythonRobotics Documentation', - 'Atsushi Sakai', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'pythonrobotics', 'PythonRobotics Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'PythonRobotics', 'PythonRobotics Documentation', - author, 'PythonRobotics', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- linkcode setting ------------------------------------------------- - -import inspect -import os -import sys -import functools - -GITHUB_REPO = "https://github.com/AtsushiSakai/PythonRobotics" -GITHUB_BRANCH = "master" - - -def linkcode_resolve(domain, info): - if domain != "py": - return None - - modname = info["module"] - fullname = info["fullname"] - - try: - module = __import__(modname, fromlist=[fullname]) - obj = functools.reduce(getattr, fullname.split("."), module) - except (ImportError, AttributeError): - return None - - try: - srcfile = inspect.getsourcefile(obj) - srcfile = get_relative_path_from_parent(srcfile, "PythonRobotics") - lineno = inspect.getsourcelines(obj)[1] - except Exception: - return None - - return f"{GITHUB_REPO}/blob/{GITHUB_BRANCH}/{srcfile}#L{lineno}" - - -def get_relative_path_from_parent(file_path: str, parent_dir: str): - path = Path(file_path).resolve() - - try: - parent_path = next(p for p in path.parents if p.name == parent_dir) - return str(path.relative_to(parent_path)) - except StopIteration: - raise ValueError(f"Parent directory '{parent_dir}' not found in {file_path}") diff --git a/docs/doc_requirements.txt b/docs/doc_requirements.txt deleted file mode 100644 index b29f4ba2891..00000000000 --- a/docs/doc_requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -sphinx == 7.2.6 # For sphinx documentation -sphinx_rtd_theme == 2.0.0 -IPython == 8.20.0 # For sphinx documentation -sphinxcontrib-napoleon == 0.7 # For auto doc -sphinx-copybutton -sphinx-rtd-dark-mode diff --git a/docs/index_main.rst b/docs/index_main.rst deleted file mode 100644 index 65634f32e81..00000000000 --- a/docs/index_main.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. PythonRobotics documentation master file, created by - sphinx-quickstart on Sat Sep 15 13:15:55 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to PythonRobotics's documentation! -========================================== - -"PythonRobotics" is a Python code collections and textbook -(This document) for robotics algorithm, which is developed on `GitHub`_. - -See this section (:ref:`What is PythonRobotics?`) for more details of this project. - -This project is `the one of the most popular open-source software (OSS) in -the field of robotics on GitHub`_. -This is `user comments about this project`_, and -this graph shows GitHub star history of this project: - -.. image:: https://api.star-history.com/svg?repos=AtsushiSakai/PythonRobotics&type=Date - :alt: Star History - :width: 80% - :align: center - - -.. _GitHub: https://github.com/AtsushiSakai/PythonRobotics -.. _`user comments about this project`: https://github.com/AtsushiSakai/PythonRobotics/blob/master/users_comments.md -.. _`MIT license`: https://github.com/AtsushiSakai/PythonRobotics/blob/master/LICENSE -.. _`the one of the most popular open-source software (OSS) in the field of robotics on GitHub`: https://github.com/topics/robotics - ----------------------------------- - -.. toctree:: - :maxdepth: 2 - :caption: Table of Contents - - modules/0_getting_started/0_getting_started - modules/1_introduction/introduction - modules/2_localization/localization - modules/3_mapping/mapping - modules/4_slam/slam - modules/5_path_planning/path_planning - modules/6_path_tracking/path_tracking - modules/7_arm_navigation/arm_navigation - modules/8_aerial_navigation/aerial_navigation - modules/9_bipedal/bipedal - modules/10_inverted_pendulum/inverted_pendulum - modules/13_mission_planning/mission_planning - modules/11_utils/utils - modules/12_appendix/appendix - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 07dcebea417..00000000000 --- a/docs/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build -set SPHINXPROJ=PythonRobotics - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/modules/0_getting_started/0_getting_started_main.rst b/docs/modules/0_getting_started/0_getting_started_main.rst deleted file mode 100644 index cb2cba47841..00000000000 --- a/docs/modules/0_getting_started/0_getting_started_main.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _`getting started`: - -Getting Started -=============== - -.. toctree:: - :maxdepth: 2 - :caption: Contents - - 1_what_is_python_robotics - 2_how_to_run_sample_codes - 3_how_to_contribute - 4_how_to_read_textbook diff --git a/docs/modules/0_getting_started/1_what_is_python_robotics_main.rst b/docs/modules/0_getting_started/1_what_is_python_robotics_main.rst deleted file mode 100644 index 2a7bd574f0b..00000000000 --- a/docs/modules/0_getting_started/1_what_is_python_robotics_main.rst +++ /dev/null @@ -1,130 +0,0 @@ -.. _`What is PythonRobotics?`: - -What is PythonRobotics? ------------------------- - -This is an Open Source Software (OSS) project: PythonRobotics, which is a Python code collection of robotics algorithms. -These codes are developed under `MIT license`_ and on `GitHub`_. - -.. _GitHub: https://github.com/AtsushiSakai/PythonRobotics -.. _`MIT license`: https://github.com/AtsushiSakai/PythonRobotics/blob/master/LICENSE - -This project has three main philosophies below: - -Philosophy 1. Easy to understand each algorithm's basic idea. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The goal is for beginners in robotics to understand the basic ideas behind each algorithm. - -`Python`_ programming language is adopted in this project to achieve the goal. -Python is a high-level programming language that is easy to read and write. -If the code is not easy to read, it would be difficult to achieve our goal of -allowing beginners to understand the algorithms. -Python has great libraries for matrix operation, mathematical and scientific operation, -and visualization, which makes code more readable because such operations -don’t need to be re-implemented. -Having the core Python packages allows the user to focus on the algorithms, -rather than the implementations. - -PythonRobotics provides not only the code but also intuitive animations that -visually demonstrate the process and behavior of each algorithm over time. -This is an example of an animation gif file that shows the process of the -path planning in a highway scenario for autonomous vehicle. - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/high_speed_and_velocity_keeping_frenet_path.gif - -This animation is a gif file and is created using the `Matplotlib`_ library. -All animation gif files are stored in the `PythonRoboticsGifs`_ repository and -all animation movies are also uploaded to this `YouTube channel`_. - -PythonRobotics also provides a textbook that explains the basic ideas of each algorithm. -The PythonRobotics textbook allows you to learn fundamental algorithms used in -robotics with minimal mathematical formulas and textual explanations, -based on PythonRobotics’ sample codes and animations. -The contents of this document, like the code, are managed in the PythonRobotics -`GitHub`_ repository and converted into HTML-based online documents using `Sphinx`_, -which is a Python-based documentation builder. -Please refer to this section ":ref:`How to read this textbook`" for information on -how to read this document for learning. - - -.. _`Python`: https://www.python.org/ -.. _`PythonRoboticsGifs`: https://github.com/AtsushiSakai/PythonRoboticsGifs -.. _`YouTube channel`: https://youtube.com/playlist?list=PL12URV8HFpCozuz0SDxke6b2ae5UZvIwa&si=AH2fNPPYufPtK20S - - -Philosophy 2. Widely used and practical algorithms are selected. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The second philosophy is that implemented algorithms have to be practical -and widely used in both academia and industry. -We believe learning these algorithms will be useful in many applications. -For example, Kalman filters and particle filter for localization, -grid mapping for mapping, -dynamic programming based approaches and sampling based approaches for path planning, -and optimal control based approach for path tracking. -These algorithms are implemented and explained in the textbook in this project. - -Philosophy 3. Minimum dependency. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Each sample code of PythonRobotics is written in Python3 and only depends on -some standard modules for readability and ease to setup and use. - - -.. _`Requirements`: - -Requirements -============ - -PythonRobotics depends only on the following five libraries, -including Python itself, to run each sample code. - -- `Python 3.12.x`_ (for Python runtime) -- `NumPy`_ (for matrix operation) -- `SciPy`_ (for scientific operation) -- `cvxpy`_ (for convex optimization) -- `Matplotlib`_ (for visualization) - -If you only need to run the code, the five libraries mentioned above are sufficient. -However, for code development or creating documentation for the textbook, -the following additional libraries are required. - -- `pytest`_ (for unit tests) -- `pytest-xdist`_ (for parallel unit tests) -- `mypy`_ (for type check) -- `Sphinx`_ (for document generation) -- `ruff`_ (for code style check) - -.. _`Python 3.12.x`: https://www.python.org/ -.. _`NumPy`: https://numpy.org/ -.. _`SciPy`: https://scipy.org/ -.. _`Matplotlib`: https://matplotlib.org/ -.. _`cvxpy`: https://www.cvxpy.org/ -.. _`pytest`: https://docs.pytest.org/en/latest/ -.. _`pytest-xdist`: https://github.com/pytest-dev/pytest-xdist -.. _`mypy`: https://mypy-lang.org/ -.. _`Sphinx`: https://www.sphinx-doc.org/en/master/index.html -.. _`ruff`: https://github.com/astral-sh/ruff - -For instructions on installing the above libraries, please refer to -this section ":ref:`How to run sample codes`". - -Audio overview of this project -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For an audio overview of this project, please refer to this `YouTube video`_. - -.. _`YouTube video`: https://www.youtube.com/watch?v=uMeRnNoJAfU - -Arxiv paper -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We have published a paper on this project on Arxiv in 2018. - -See this paper for more details about this Project: - -- `PythonRobotics: a Python code collection of robotics algorithms`_ (`BibTeX`_) - -.. _`PythonRobotics: a Python code collection of robotics algorithms`: https://arxiv.org/abs/1808.10703 -.. _`BibTeX`: https://github.com/AtsushiSakai/PythonRoboticsPaper/blob/master/python_robotics.bib - diff --git a/docs/modules/0_getting_started/2_how_to_run_sample_codes_main.rst b/docs/modules/0_getting_started/2_how_to_run_sample_codes_main.rst deleted file mode 100644 index b92fc9bde0f..00000000000 --- a/docs/modules/0_getting_started/2_how_to_run_sample_codes_main.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. _`How to run sample codes`: - -How to run sample codes -------------------------- - -In this chapter, we will explain the setup process for running each sample code -in PythonRobotics and describe the contents of each directory. - -Steps to setup and run sample codes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Install `Python 3.12.x`_ - -Note that older versions of Python3 might work, but we recommend using -the specified version, because the sample codes are only tested with it. - -2. If you prefer to use conda for package management, install -Anaconda or Miniconda to use `conda`_ command. - -3. Clone this repo and go into dir. - -.. code-block:: - - >$ git clone https://github.com/AtsushiSakai/PythonRobotics.git - - >$ cd PythonRobotics - - -4. Install the required libraries. - -We have prepared requirements management files for `conda`_ and `pip`_ under -the requirements directory. Using these files makes it easy to install the necessary libraries. - -using conda : - -.. code-block:: - - >$ conda env create -f requirements/environment.yml - -using pip : - -.. code-block:: - - >$ pip install -r requirements/requirements.txt - - -5. Execute python script in each directory. - -For example, to run the sample code of `Extented Kalman Filter` in the -`localization` directory, execute the following command: - -.. code-block:: - - >$ cd localization/extended_kalman_filter - - >$ python extended_kalman_filter.py - -Then, you can see this animation of the EKF algorithm based localization: - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/extended_kalman_filter/animation.gif - -Please refer to the `Directory structure`_ section for more details on the contents of each directory. - -6. Add star to this repo if you like it 😃. - -.. _`Python 3.12.x`: https://www.python.org/ -.. _`conda`: https://docs.conda.io/projects/conda/en/stable/user-guide/install/index.html -.. _`pip`: https://pip.pypa.io/en/stable/ -.. _`the requirements directory`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/requirements - -.. _`Directory structure`: - -Directory structure -~~~~~~~~~~~~~~~~~~~~ - -The top-level directory structure of PythonRobotics is as follows: - -Sample codes directories: - -- `AerialNavigation`_ : the sample codes of aerial navigation algorithms for drones and rocket landing. -- `ArmNavigation`_ : the sample codes of arm navigation algorithms for robotic arms. -- `Localization`_ : the sample codes of localization algorithms. -- `Bipedal`_ : the sample codes of bipedal walking algorithms for legged robots. -- `Control`_ : the sample codes of control algorithms for robotic systems. -- `Mapping`_ : the sample codes of mapping or obstacle shape recognition algorithms. -- `PathPlanning`_ : the sample codes of path planning algorithms. -- `PathTracking`_ : the sample codes of path tracking algorithms for car like robots. -- `SLAM`_ : the sample codes of SLAM algorithms. - -Other directories: - -- `docs`_ : This directory contains the documentation of PythonRobotics. -- `requirements`_ : This directory contains the requirements management files. -- `tests`_ : This directory contains the unit test files. -- `utils`_ : This directory contains utility functions used in some sample codes in common. -- `.github`_ : This directory contains the GitHub Actions configuration files. -- `.circleci`_ : This directory contains the CircleCI configuration files. - -The structure of this document is the same as that of the sample code -directories mentioned above. -For more details, please refer to the :ref:`How to read this textbook` section. - - -.. _`AerialNavigation`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/AerialNavigation -.. _`ArmNavigation`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/ArmNavigation -.. _`Localization`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/Localization -.. _`Bipedal`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/Bipedal -.. _`Control`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/Control -.. _`Mapping`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/Mapping -.. _`PathPlanning`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/PathPlanning -.. _`PathTracking`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/PathTracking -.. _`SLAM`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/SLAM -.. _`docs`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/docs -.. _`requirements`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/requirements -.. _`tests`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/tests -.. _`utils`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/utils -.. _`.github`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/.github -.. _`.circleci`: https://github.com/AtsushiSakai/PythonRobotics/tree/master/.circleci diff --git a/docs/modules/0_getting_started/4_how_to_read_textbook_main.rst b/docs/modules/0_getting_started/4_how_to_read_textbook_main.rst deleted file mode 100644 index 1625c838afa..00000000000 --- a/docs/modules/0_getting_started/4_how_to_read_textbook_main.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _`How to read this textbook`: - -How to read this textbook --------------------------- - -This document is structured to help you learn the fundamental concepts -behind each sample code in PythonRobotics. - -If you already have some knowledge of robotics technologies, you can start -by reading any document that interests you. - -However, if you have no prior knowledge of robotics technologies, it is -recommended that you first read the :ref:`Introduction` section and then proceed -to the documents related to the technical fields that interest you. \ No newline at end of file diff --git a/docs/modules/12_appendix/external_sensors_main.rst b/docs/modules/12_appendix/external_sensors_main.rst deleted file mode 100644 index 3597418150c..00000000000 --- a/docs/modules/12_appendix/external_sensors_main.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. _`External Sensors for Robots`: - -External Sensors for Robots -============================ - -This project, `PythonRobotics`, focuses on algorithms, so hardware is not included. -However, having basic knowledge of hardware in robotics is also important for understanding algorithms. -Therefore, we will provide an overview. - -Introduction ------------- - -In recent years, the application of robotic technology has advanced, -particularly in areas such as autonomous vehicles and disaster response robots. -A crucial element in these technologies is external recognition—the robot's ability to understand its surrounding environment, identify safe zones, and detect moving objects using onboard sensors. Achieving effective external recognition involves various techniques, but equally important is the selection of appropriate sensors. Robots, like the sensors they employ, come in many forms, but external recognition sensors can be broadly categorized into three types. Developing an advanced external recognition system requires a thorough understanding of each sensor's principles and characteristics to determine their optimal application. This article summarizes the principles and features of these sensors for personal study purposes. - -Laser Sensors -------------- - -Laser sensors measure distances by utilizing light, commonly referred to as Light Detection and Ranging (LIDAR). They operate by emitting light towards an object and calculating the distance based on the time it takes for the reflected light to return, using the speed of light as a constant. - -Radar Sensors -------------- - -TBD - - -Monocular Cameras ------------------ - -Monocular cameras utilize a single camera to recognize the external environment. Compared to other sensors, they can detect color and brightness information, making them primarily useful for object recognition. However, they face challenges in independently measuring distances to surrounding objects and may struggle in low-light or dark conditions. - -Requirements for Cameras and Image Processing in Robotics -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -While camera sensors are widely used in applications like surveillance, deploying them in robotics necessitates meeting specific requirements: - -1. High dynamic range to adapt to various lighting conditions -2. Wide measurement range -3. Capability for three-dimensional measurement through techniques like motion stereo -4. Real-time processing with high frame rates -5. Cost-effectiveness - -Stereo Cameras --------------- - -Stereo cameras employ multiple cameras to measure distances to surrounding objects. By knowing the positions and orientations of each camera and analyzing the disparity in the images (parallax), the distance to a specific point (the object represented by a particular pixel) can be calculated. - -Characteristics of Stereo Cameras -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Advantages of stereo cameras include the ability to obtain high-precision and high-density distance information at close range, depending on factors like camera resolution and the distance between cameras (baseline). This makes them suitable for indoor robots that require precise shape recognition of nearby objects. Additionally, stereo cameras are relatively cost-effective compared to other sensors, leading to their use in consumer products like Subaru's EyeSight system. However, stereo cameras are less effective for long-distance measurements due to a decrease in accuracy proportional to the square of the distance. They are also susceptible to environmental factors such as lighting conditions. - -Ultrasonic Sensors ------------------- - -Ultrasonic sensors are commonly used in indoor robots and some automotive autonomous driving systems. Their features include affordability compared to laser or radar sensors, the ability to detect very close objects, and the capability to sense materials like glass, which may be challenging for lasers or cameras. However, they have limitations such as shorter maximum measurement distances and lower resolution and accuracy. - -References ----------- - -TBD diff --git a/docs/modules/12_appendix/internal_sensors_main.rst b/docs/modules/12_appendix/internal_sensors_main.rst deleted file mode 100644 index 18f209098ea..00000000000 --- a/docs/modules/12_appendix/internal_sensors_main.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. _`Internal Sensors for Robots`: - -Internal Sensors for Robots -============================ - -This project, `PythonRobotics`, focuses on algorithms, so hardware is not included. -However, having basic knowledge of hardware in robotics is also important for understanding algorithms. -Therefore, we will provide an overview. - -Introduction ------------- - -Global Navigation Satellite System (GNSS) -------------------------------------------- - -Gyroscope ----------- - -Accelerometer --------------- - -Magnetometer --------------- - -Inertial Measurement Unit (IMU) --------------------------------- - -Pressure Sensor ------------------ - -Temperature Sensor --------------------- - - diff --git a/docs/modules/12_appendix/steering_motion_model/steering_model.png b/docs/modules/12_appendix/steering_motion_model/steering_model.png deleted file mode 100644 index c66dded87af..00000000000 Binary files a/docs/modules/12_appendix/steering_motion_model/steering_model.png and /dev/null differ diff --git a/docs/modules/12_appendix/steering_motion_model/turning_radius_calc1.png b/docs/modules/12_appendix/steering_motion_model/turning_radius_calc1.png deleted file mode 100644 index 3de7ed8797c..00000000000 Binary files a/docs/modules/12_appendix/steering_motion_model/turning_radius_calc1.png and /dev/null differ diff --git a/docs/modules/12_appendix/steering_motion_model/turning_radius_calc2.png b/docs/modules/12_appendix/steering_motion_model/turning_radius_calc2.png deleted file mode 100644 index f7e776bf409..00000000000 Binary files a/docs/modules/12_appendix/steering_motion_model/turning_radius_calc2.png and /dev/null differ diff --git a/docs/modules/12_appendix/steering_motion_model_main.rst b/docs/modules/12_appendix/steering_motion_model_main.rst deleted file mode 100644 index 6e444b7909b..00000000000 --- a/docs/modules/12_appendix/steering_motion_model_main.rst +++ /dev/null @@ -1,97 +0,0 @@ - -Steering Motion Model ------------------------ - -Turning radius calculation by steering motion model -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The turning Radius represents the radius of the circle when the robot turns, as shown in the diagram below. - -.. image:: steering_motion_model/steering_model.png - -When the steering angle is tilted by :math:`\delta`, -the turning radius :math:`R` can be calculated using the following equation, -based on the geometric relationship between the wheelbase (WB), -which is the distance between the rear wheel center and the front wheel center, -and the assumption that the turning radius circle passes through the center of -the rear wheels in the diagram above. - -:math:`R = \frac{WB}{tan\delta}` - -The curvature :math:`\kappa` is the reciprocal of the turning radius: - -:math:`\kappa = \frac{tan\delta}{WB}` - -In the diagram above, the angular difference :math:`\Delta \theta` in the vehicle’s heading between two points on the turning radius :math:`R` -is the same as the angle of the vector connecting the two points from the center of the turn. - -From the formula for the length of an arc and the radius, - -:math:`\Delta \theta = \frac{s}{R}` - -Here, :math:`s` is the distance between two points on the turning radius. - -So, yaw rate :math:`\omega` can be calculated as follows. - -:math:`\omega = \frac{v}{R}` - -and - -:math:`\omega = v\kappa` - -here, :math:`v` is the velocity of the vehicle. - - -Turning radius calculation by 2 consecutive positions of the robot trajectory -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In this section, we will derive the formula for the turning radius from 2 consecutive positions of the robot trajectory. - -.. image:: steering_motion_model/turning_radius_calc1.png - -As shown in the upper diagram above, the robot moves from a point at time :math:`t` to a point at time :math:`t+1`. -Each point is represented by a 2D position :math:`(x_t, y_t)` and an orientation :math:`\theta_t`. - -The distance between the two points is :math:`d = \sqrt{(x_{t+1} - x_t)^2 + (y_{t+1} - y_t)^2}`. - -The angle between the two vectors from the turning center to the two points is :math:`\theta = \theta_{t+1} - \theta_t`. -Here, by drawing a perpendicular line from the center of the turning radius -to a straight line of length :math:`d` connecting two points, -the following equation can be derived from the resulting right triangle. - -:math:`sin\frac{\theta}{2} = \frac{d}{2R}` - -So, the turning radius :math:`R` can be calculated as follows. - -:math:`R = \frac{d}{2sin\frac{\theta}{2}}` - -The curvature :math:`\kappa` is the reciprocal of the turning radius. -So, the curvature can be calculated as follows. - -:math:`\kappa = \frac{2sin\frac{\theta}{2}}{d}` - -Target speed by maximum steering speed -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If the maximum steering speed is given as :math:`\dot{\delta}_{max}`, -the maximum curvature change rate :math:`\dot{\kappa}_{max}` can be calculated as follows: - -:math:`\dot{\kappa}_{max} = \frac{tan\dot{\delta}_{max}}{WB}` - -From the curvature calculation by 2 consecutive positions of the robot trajectory, - -the maximum curvature change rate :math:`\dot{\kappa}_{max}` can be calculated as follows: - -:math:`\dot{\kappa}_{max} = \frac{\kappa_{t+1}-\kappa_{t}}{\Delta t}` - -If we can assume that the vehicle will not exceed the maximum curvature change rate, - -the target minimum velocity :math:`v_{min}` can be calculated as follows: - -:math:`v_{min} = \frac{d_{t+1}+d_{t}}{\Delta t} = \frac{d_{t+1}+d_{t}}{(\kappa_{t+1}-\kappa_{t})}\frac{tan\dot{\delta}_{max}}{WB}` - - -References: -~~~~~~~~~~~ - -- `Vehicle Dynamics and Control <https://link.springer.com/book/10.1007/978-1-4614-1433-9>`_ diff --git a/docs/modules/13_mission_planning/behavior_tree/behavior_tree_main.rst b/docs/modules/13_mission_planning/behavior_tree/behavior_tree_main.rst deleted file mode 100644 index ae3e16da818..00000000000 --- a/docs/modules/13_mission_planning/behavior_tree/behavior_tree_main.rst +++ /dev/null @@ -1,104 +0,0 @@ -Behavior Tree -------------- - -Behavior Tree is a modular, hierarchical decision model that is widely used in robot control, and game development. -It present some similarities to hierarchical state machines with the key difference that the main building block of a behavior is a task rather than a state. -Behavior Tree have been shown to generalize several other control architectures (https://ieeexplore.ieee.org/document/7790863) - -Core Concepts -~~~~~~~~~~~~~ - -Control Node -++++++++++++ - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.ControlNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.SequenceNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.SelectorNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.WhileDoElseNode - -Action Node -++++++++++++ - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.ActionNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.EchoNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.SleepNode - -Decorator Node -++++++++++++++ - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.DecoratorNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.InverterNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.TimeoutNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.DelayNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.ForceSuccessNode - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.ForceFailureNode - -Behavior Tree Factory -+++++++++++++++++++++ - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.BehaviorTreeFactory - :members: - -Behavior Tree -+++++++++++++ - -.. autoclass:: MissionPlanning.BehaviorTree.behavior_tree.BehaviorTree - :members: - -Example -~~~~~~~ - -Visualize the behavior tree by `xml-tree-visual <https://xml-tree-visual.vercel.app/>`_. - -.. image:: ./robot_behavior_case.svg - -Print the behavior tree - -.. code-block:: text - - Behavior Tree - [Robot Main Controller] - [Battery Management] - (Low Battery Detection) - <Check Battery> - <Low Battery Warning> - <Charge Battery> - [Patrol Task] - <Start Task> - [Move to Position A] - <Move to A> - [Obstacle Handling A] - [Obstacle Present] - <Detect Obstacle> - <Avoid Obstacle> - <No Obstacle> - <Position A Task> - [Move to Position B] - (Short Wait) - <Prepare Movement> - <Move to B> - (Limited Time Obstacle Handling) - [Obstacle Present] - <Detect Obstacle> - <Avoid Obstacle> - <Position B Task> - [Conditional Move to C] - <Check Sufficient Battery> - [Perform Position C Task] - <Move to C> - (Ensure Completion) - <Position C Task> - <Skip Position C> - <Complete Patrol> - <Return to Charging Station> - Behavior Tree diff --git a/docs/modules/13_mission_planning/behavior_tree/robot_behavior_case.svg b/docs/modules/13_mission_planning/behavior_tree/robot_behavior_case.svg deleted file mode 100644 index a3d43aed525..00000000000 --- a/docs/modules/13_mission_planning/behavior_tree/robot_behavior_case.svg +++ /dev/null @@ -1,22 +0,0 @@ -<svg width="2870" height="795" id="tree-svg" style="overflow: visible;" xmlns="http://www.w3.org/2000/svg" viewBox="-1560 -65 4380 810"><style xmlns="http://www.w3.org/1999/xhtml"> - .node rect { - fill: #fff; - stroke-width: 1px; - } - .node text { - font: 12px sans-serif; - } - .node-attributes { - font: 10px sans-serif; - fill: #666; - } - .link { - fill: none; - stroke: #999; - stroke-width: 1px; - } - line { - stroke: #444; - stroke-width: 2px; - } - </style><g transform="translate(75,112) scale(0.8)"><path class="link" d="M0,0C0,60,-1125,60,-1125,120"/><path class="link" d="M0,0C0,60,1125,60,1125,120"/><path class="link" d="M-1125,120C-1125,180,-1395,180,-1395,240"/><path class="link" d="M-1125,120C-1125,180,-1125,180,-1125,240"/><path class="link" d="M-1125,120C-1125,180,-855,180,-855,240"/><path class="link" d="M1125,120C1125,180,-405,180,-405,240"/><path class="link" d="M1125,120C1125,180,-135,180,-135,240"/><path class="link" d="M1125,120C1125,180,990,180,990,240"/><path class="link" d="M1125,120C1125,180,2115,180,2115,240"/><path class="link" d="M1125,120C1125,180,2385,180,2385,240"/><path class="link" d="M1125,120C1125,180,2655,180,2655,240"/><path class="link" d="M-1395,240C-1395,300,-1395,300,-1395,360"/><path class="link" d="M-135,240C-135,300,-405,300,-405,360"/><path class="link" d="M-135,240C-135,300,-135,300,-135,360"/><path class="link" d="M-135,240C-135,300,135,300,135,360"/><path class="link" d="M990,240C990,300,585,300,585,360"/><path class="link" d="M990,240C990,300,855,300,855,360"/><path class="link" d="M990,240C990,300,1125,300,1125,360"/><path class="link" d="M990,240C990,300,1395,300,1395,360"/><path class="link" d="M2115,240C2115,300,1845,300,1845,360"/><path class="link" d="M2115,240C2115,300,2115,300,2115,360"/><path class="link" d="M2115,240C2115,300,2385,300,2385,360"/><path class="link" d="M-135,360C-135,420,-270,420,-270,480"/><path class="link" d="M-135,360C-135,420,0,420,0,480"/><path class="link" d="M585,360C585,420,585,420,585,480"/><path class="link" d="M1125,360C1125,420,1125,420,1125,480"/><path class="link" d="M2115,360C2115,420,1980,420,1980,480"/><path class="link" d="M2115,360C2115,420,2250,420,2250,480"/><path class="link" d="M-270,480C-270,540,-405,540,-405,600"/><path class="link" d="M-270,480C-270,540,-135,540,-135,600"/><path class="link" d="M1125,480C1125,540,990,540,990,600"/><path class="link" d="M1125,480C1125,540,1260,540,1260,600"/><path class="link" d="M2250,480C2250,540,2250,540,2250,600"/><g class="node" transform="translate(0,0)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Selector</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Robot Main Controller</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-1125,120)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Battery Management</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1125,120)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Patrol Task</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-1395,240)"><rect x="-115" y="-15" width="230" height="50" stroke="#F5A623" style="stroke: rgb(245, 166, 35);"/><text dy="5" text-anchor="middle">Inverter</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Low Battery Detection</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-1125,240)"><rect x="-115" y="-15" width="230" height="90" stroke="#D0021B" style="stroke: rgb(208, 2, 27);"/><text dy="5" text-anchor="middle">Echo</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Low Battery Warning</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">message: Battery level low!</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">Charging needed</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-855,240)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">ChargeBattery</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Charge Battery</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">charge_rate: 20</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-405,240)"><rect x="-115" y="-15" width="230" height="70" stroke="#D0021B" style="stroke: rgb(208, 2, 27);"/><text dy="5" text-anchor="middle">Echo</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Start Task</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">message: Starting patrol task</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-135,240)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Move to Position A</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(990,240)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Move to Position B</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2115,240)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">WhileDoElse</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Conditional Move to C</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2385,240)"><rect x="-115" y="-15" width="230" height="110" stroke="#D0021B" style="stroke: rgb(208, 2, 27);"/><text dy="5" text-anchor="middle">Echo</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Complete Patrol</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">message: Patrol task</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">completed, returning to</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="85" x="-105" text-anchor="start">charging station</text><line x1="-105" y1="90" x2="105" y2="90" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2655,240)"><rect x="-115" y="-15" width="230" height="110" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">MoveToPosition</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Return to Charging</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">Station</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">position: Charging Station</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="85" x="-105" text-anchor="start">move_duration: 4</text><line x1="-105" y1="90" x2="105" y2="90" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-1395,360)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">CheckBattery</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Check Battery</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">threshold: 30</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-405,360)"><rect x="-115" y="-15" width="230" height="90" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">MoveToPosition</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Move to A</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">position: A</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">move_duration: 2</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-135,360)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Selector</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Obstacle Handling A</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(135,360)"><rect x="-115" y="-15" width="230" height="90" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">PerformTask</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Position A Task</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">task_name: Check Device Status</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">task_duration: 2</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(585,360)"><rect x="-115" y="-15" width="230" height="70" stroke="#F5A623" style="stroke: rgb(245, 166, 35);"/><text dy="5" text-anchor="middle">Delay</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Short Wait</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">sec: 1</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(855,360)"><rect x="-115" y="-15" width="230" height="90" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">MoveToPosition</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Move to B</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">position: B</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">move_duration: 3</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1125,360)"><rect x="-115" y="-15" width="230" height="90" stroke="#F5A623" style="stroke: rgb(245, 166, 35);"/><text dy="5" text-anchor="middle">Timeout</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Limited Time Obstacle</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">Handling</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">sec: 2</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1395,360)"><rect x="-115" y="-15" width="230" height="90" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">PerformTask</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Position B Task</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">task_name: Data Collection</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">task_duration: 2.5</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1845,360)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">CheckBattery</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Check Sufficient Battery</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">threshold: 50</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2115,360)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Perform Position C Task</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2385,360)"><rect x="-115" y="-15" width="230" height="90" stroke="#D0021B" style="stroke: rgb(208, 2, 27);"/><text dy="5" text-anchor="middle">Echo</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Skip Position C</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">message: Insufficient power,</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">skipping position C task</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-270,480)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Obstacle Present</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(0,480)"><rect x="-115" y="-15" width="230" height="70" stroke="#D0021B" style="stroke: rgb(208, 2, 27);"/><text dy="5" text-anchor="middle">Echo</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: No Obstacle</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">message: Path clear</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(585,480)"><rect x="-115" y="-15" width="230" height="90" stroke="#D0021B" style="stroke: rgb(208, 2, 27);"/><text dy="5" text-anchor="middle">Echo</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Prepare Movement</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">message: Preparing to move to</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">next position</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1125,480)"><rect x="-115" y="-15" width="230" height="50" stroke="#4A90E2" style="stroke: rgb(74, 144, 226);"/><text dy="5" text-anchor="middle">Sequence</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Obstacle Present</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1980,480)"><rect x="-115" y="-15" width="230" height="90" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">MoveToPosition</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Move to C</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">position: C</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">move_duration: 2.5</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2250,480)"><rect x="-115" y="-15" width="230" height="50" stroke="#F5A623" style="stroke: rgb(245, 166, 35);"/><text dy="5" text-anchor="middle">ForceSuccess</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Ensure Completion</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-405,600)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">DetectObstacle</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Detect Obstacle</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">obstacle_probability: 0.3</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(-135,600)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">AvoidObstacle</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Avoid Obstacle</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">avoid_duration: 1.5</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(990,600)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">DetectObstacle</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Detect Obstacle</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">obstacle_probability: 0.4</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(1260,600)"><rect x="-115" y="-15" width="230" height="70" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">AvoidObstacle</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Avoid Obstacle</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">avoid_duration: 1.8</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/></g><g class="node" transform="translate(2250,600)"><rect x="-115" y="-15" width="230" height="110" stroke="#90EE90" style="stroke: rgb(144, 238, 144);"/><text dy="5" text-anchor="middle">PerformTask</text><line x1="-105" y1="10" x2="105" y2="10" stroke="#444" stroke-width="2"/><text class="node-attributes" dy="25" x="-105" text-anchor="start">name: Position C Task</text><line x1="-105" y1="30" x2="105" y2="30" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="45" x="-105" text-anchor="start">task_name: Environment</text><line x1="-105" y1="50" x2="105" y2="50" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="65" x="-105" text-anchor="start">Monitoring</text><line x1="-105" y1="70" x2="105" y2="70" stroke="#ddd" stroke-width="1"/><text class="node-attributes" dy="85" x="-105" text-anchor="start">task_duration: 2</text><line x1="-105" y1="90" x2="105" y2="90" stroke="#ddd" stroke-width="1"/></g></g></svg> \ No newline at end of file diff --git a/docs/modules/13_mission_planning/mission_planning_main.rst b/docs/modules/13_mission_planning/mission_planning_main.rst deleted file mode 100644 index c35eacd8d5e..00000000000 --- a/docs/modules/13_mission_planning/mission_planning_main.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _`Mission Planning`: - -Mission Planning -================ - -Mission planning includes tools such as finite state machines and behavior trees used to describe robot behavior and high level task planning. - -.. toctree:: - :maxdepth: 2 - :caption: Contents - - state_machine/state_machine - behavior_tree/behavior_tree diff --git a/docs/modules/13_mission_planning/state_machine/robot_behavior_case.png b/docs/modules/13_mission_planning/state_machine/robot_behavior_case.png deleted file mode 100644 index fbc1369cbcd..00000000000 Binary files a/docs/modules/13_mission_planning/state_machine/robot_behavior_case.png and /dev/null differ diff --git a/docs/modules/13_mission_planning/state_machine/state_machine_main.rst b/docs/modules/13_mission_planning/state_machine/state_machine_main.rst deleted file mode 100644 index abaece1b115..00000000000 --- a/docs/modules/13_mission_planning/state_machine/state_machine_main.rst +++ /dev/null @@ -1,74 +0,0 @@ -State Machine -------------- - -A state machine is a model used to describe the transitions of an object between different states. It clearly shows how an object changes state based on events and may trigger corresponding actions. - -Core Concepts -~~~~~~~~~~~~~ - -- **State**: A distinct mode or condition of the system (e.g. "Idle", "Running"). Managed by State class with optional on_enter/on_exit callbacks -- **Event**: A trigger signal that may cause state transitions (e.g. "start", "stop") -- **Transition**: A state change path from source to destination state triggered by an event -- **Action**: An operation executed during transition (before entering new state) -- **Guard**: A precondition that must be satisfied to allow transition - -API -~~~ - -.. autoclass:: MissionPlanning.StateMachine.state_machine.StateMachine - :members: add_transition, process, register_state - :special-members: __init__ - -PlantUML Support -~~~~~~~~~~~~~~~~ - -The ``generate_plantuml()`` method creates diagrams showing: - -- Current state (marked with [*] arrow) -- All possible transitions -- Guard conditions in [brackets] -- Actions prefixed with / - -Example -~~~~~~~ - -state machine diagram: -+++++++++++++++++++++++ -.. image:: robot_behavior_case.png - -state transition table: -+++++++++++++++++++++++ -.. list-table:: State Transitions - :header-rows: 1 - :widths: 20 15 20 20 20 - - * - Source State - - Event - - Target State - - Guard - - Action - * - patrolling - - detect_task - - executing_task - - - - - * - executing_task - - task_complete - - patrolling - - - - reset_task - * - executing_task - - low_battery - - returning_to_base - - is_battery_low - - - * - returning_to_base - - reach_base - - charging - - - - - * - charging - - charge_complete - - patrolling - - - - \ No newline at end of file diff --git a/docs/modules/1_introduction/1_definition_of_robotics/definition_of_robotics_main.rst b/docs/modules/1_introduction/1_definition_of_robotics/definition_of_robotics_main.rst deleted file mode 100644 index ca595301a6f..00000000000 --- a/docs/modules/1_introduction/1_definition_of_robotics/definition_of_robotics_main.rst +++ /dev/null @@ -1,107 +0,0 @@ -Definition of Robotics ----------------------- - -This section explains the definition, history, key components, and applications of robotics. - -What is Robotics? -^^^^^^^^^^^^^^^^^^ - -Robot is a machine that can perform tasks automatically or semi-autonomously. -Robotics is the study of robots. - -The word “robot” comes from the Czech word “robota,” which means “forced labor” or “drudgery.” -It was first used in the 1920 science fiction play `R.U.R.`_ (Rossum’s Universal Robots) -by the Czech writer `Karel Čapek`_. -In the play, robots were artificial workers created to serve humans, but they eventually rebelled. - -Over time, “robot” came to refer to machines or automated systems that can perform tasks, -often with some level of intelligence or autonomy. - -Currently, 2 millions robots are working in the world, and the number is increasing every year. -In South Korea, where the adoption of robots is particularly rapid, -50 robots are operating per 1,000 people. - -.. _`R.U.R.`: https://thereader.mitpress.mit.edu/origin-word-robot-rur/ -.. _`Karel Čapek`: https://en.wikipedia.org/wiki/Karel_%C4%8Capek - -The History of Robots -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This timeline highlights key milestones in the history of robotics: - -Ancient and Early Concepts (Before 1500s) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The idea of **automated machines** has existed for thousands of years. -Ancient civilizations imagined mechanical beings: - -- **Ancient Greece (4th Century BC)** – Greek engineer `Hero of Alexandria`_ designed early **automata** (self-operating machines) powered by water or air. -- **Chinese and Arabic Automata (9th–13th Century)** – Inventors like `Ismail Al-Jazari`_ created intricate mechanical devices, including water clocks and automated moving peacocks driven by hydropower. - -.. _`Hero of Alexandria`: https://en.wikipedia.org/wiki/Hero_of_Alexandria -.. _`Ismail Al-Jazari`: https://en.wikipedia.org/wiki/Ismail_al-Jazari - -The Birth of Modern Robotics (1500s–1800s) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `Leonardo da Vinci’s Robot`_ (1495) – Designed a humanoid knight with mechanical movement. -- `Jacques de Vaucanson’s Digesting Duck`_ (1738) – Created robotic figures like a mechanical duck that could "eat" and "digest." -- `Industrial Revolution`_ (18th–19th Century) – Machines began replacing human labor in factories, setting the foundation for automation. - -.. _`Leonardo da Vinci’s Robot`: https://en.wikipedia.org/wiki/Leonardo%27s_robot -.. _`Jacques de Vaucanson’s Digesting Duck`: https://en.wikipedia.org/wiki/Jacques_de_Vaucanson -.. _`Industrial Revolution`: https://en.wikipedia.org/wiki/Industrial_Revolution - -The Rise of Industrial Robots (1900s–1950s) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **The Term “Robot” (1921)** – Czech writer `Karel Čapek`_ introduced the word *“robot”* in his play `R.U.R.`_ (Rossum’s Universal Robots). -- **Early Cybernetics (1940s–1950s)** – Scientists like `Norbert Wiener`_ developed theories of self-regulating machines, influencing modern robotics (Cybernetics). - -.. _`Norbert Wiener`: https://en.wikipedia.org/wiki/Norbert_Wiener - -The Birth of Modern Robotics (1950s–1980s) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **First Industrial Robot (1961)** – `Unimate`_, created by `George Devol`_ and `Joseph Engelberger`_, was the first programmable robot used in a factory. -- **Rise of AI & Autonomous Robots (1970s–1980s)** – Researchers developed mobile robots like `Shakey`_ (Stanford, 1966) and AI-based control systems. - -.. _`Unimate`: https://en.wikipedia.org/wiki/Unimate -.. _`George Devol`: https://en.wikipedia.org/wiki/George_Devol -.. _`Joseph Engelberger`: https://en.wikipedia.org/wiki/Joseph_Engelberger -.. _`Shakey`: https://en.wikipedia.org/wiki/Shakey_the_robot - -Advanced Robotics and AI Integration (1990s–Present) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **Industrial Robots** – Advanced robots like `Baxter`_ and `Amazon Robotics`_ revolutionized manufacturing and logistics. -- **Autonomous Vehicles** – Self-driving cars for robo taxi like `Waymo`_ and autonomous haulage system in mining like `AHS`_ became more advanced and bisiness-ready. -- **Exploration Robots** – Used for planetary exploration (e.g., NASA’s `Mars rovers`_). -- **Medical Robotics** – Robots like `da Vinci Surgical System`_ revolutionized healthcare. -- **Personal Robots** – Devices like `Roomba`_ (vacuum robot) and `Sophia`_ (AI humanoid) became popular. -- **Service Robots** - Assistive robots like serving robots in restaurants and hotels like `Bellabot`_. -- **Collaborative Robots (Drones)** – Collaborative robots like UAV (Unmanned Aerial Vehicle) in drone shows and delivery services. - -.. _`Baxter`: https://en.wikipedia.org/wiki/Baxter_(robot) -.. _`Amazon Robotics`: https://en.wikipedia.org/wiki/Amazon_Robotics -.. _`Mars rovers`: https://en.wikipedia.org/wiki/Mars_rover -.. _`Waymo`: https://waymo.com/ -.. _`AHS`: https://www.futurebridge.com/industry/perspectives-industrial-manufacturing/autonomous-haulage-systems-the-future-of-mining-operations/ -.. _`da Vinci Surgical System`: https://en.wikipedia.org/wiki/Da_Vinci_Surgical_System -.. _`Roomba`: https://en.wikipedia.org/wiki/Roomba -.. _`Sophia`: https://en.wikipedia.org/wiki/Sophia_(robot) -.. _`Bellabot`: https://www.pudurobotics.com/en - -Key Components of Robotics -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Robotics consists of several essential components: - -#. Sensors – Gather information from the environment (e.g., Cameras, LiDAR, GNSS, Gyro, Accelerometer, Wheel encoders). -#. Actuators – Enable movement and interaction with the world (e.g., Motors, Hydraulic systems). -#. Computers – Process sensor data and make decisions (e.g., Micro-controllers, CPUs, GPUs). -#. Power Supply – Provides energy to run the robot (e.g., Batteries, Solar power). -#. Software & Algorithms – Allow the robot to function and make intelligent decisions (e.g., ROS, Machine learning models, Localization, Mapping, Path planning, Control). - -This project, `PythonRobotics`, focuses on the software and algorithms part of robotics. -If you are interested in `Sensors` hardware, you can check :ref:`Internal Sensors for Robots` or :ref:`External Sensors for Robots`. diff --git a/docs/modules/1_introduction/2_python_for_robotics/python_for_robotics_main.rst b/docs/modules/1_introduction/2_python_for_robotics/python_for_robotics_main.rst deleted file mode 100644 index c47c122853a..00000000000 --- a/docs/modules/1_introduction/2_python_for_robotics/python_for_robotics_main.rst +++ /dev/null @@ -1,135 +0,0 @@ -Python for Robotics ----------------------- - -A programing language, Python is used for this `PythonRobotics` project -to achieve the purposes of this project described in the :ref:`What is PythonRobotics?`. - -This section explains the Python itself and features for science computing and robotics. - -Python for general-purpose programming -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -`Python <https://www.python.org/>`_ is an general-purpose programming language developed by -`Guido van Rossum <https://en.wikipedia.org/wiki/Guido_van_Rossum>`_ from the late 1980s. - -It features as follows: - -#. High-level -#. Interpreted -#. Dynamic type system (also type annotation is supported) -#. Emphasizes code readability -#. Rapid prototyping -#. Batteries included -#. Interoperability for C and Fortran - -Due to these features, Python is one of the most popular programming language -for educational purposes for programming beginners. - -Python for Scientific Computing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Python itself was not designed for scientific computing. -However, scientists quickly recognized its strengths. -For example, - -#. High-level and interpreted features enable scientists to focus on their problems without dealing with low-level programming tasks like memory management. -#. Code readability, rapid prototyping, and batteries included features enables scientists who are not professional programmers, to solve their problems easily. -#. The interoperability to wrap C and Fortran libraries enables scientists to access already existed powerful and optimized scientific computing libraries. - -To address the more needs of scientific computing, many fundamental scientific computation libraries have been developed based on the upper features. - -- `NumPy <https://numpy.org/>`_ is the fundamental package for scientific computing with Python. -- `SciPy <https://www.scipy.org/>`_ is a library that builds on NumPy and provides a large number of functions that operate on NumPy arrays and are useful for different types of scientific and engineering applications. -- `Matplotlib <https://matplotlib.org/>`_ is a plotting library for the Python programming language and its numerical mathematics extension NumPy. -- `Pandas <https://pandas.pydata.org/>`_ is a fast, powerful, flexible, and easy-to-use open-source data analysis and data manipulation library built on top of NumPy. -- `SymPy <https://www.sympy.org/>`_ is a Python library for symbolic mathematics. -- `CVXPy <https://www.cvxpy.org/>`_ is a Python-embedded modeling language for convex optimization problems. - -Also, more domain-specific libraries have been developed based on these fundamental libraries: - -- `Scikit-learn <https://scikit-learn.org/stable/>`_ is a free software machine learning library for the Python programming language. -- `Scikit-image <https://scikit-image.org/>`_ is a collection of algorithms for image processing. -- `Networkx <https://networkx.org/>`_ is a package for the creation, manipulation for complex networks. -- `SunPy <https://sunpy.org/>`_ is a community-developed free and open-source software package for solar physics. -- `Astropy <https://www.astropy.org/>`_ is a community-developed free and open-source software package for astronomy. - -Currently, Python is one of the most popular programming languages for scientific computing. - -Python for Robotics -^^^^^^^^^^^^^^^^^^^^ - -Python has become an increasingly popular language in robotics. - -These are advantages of Python for Robotics: - -Simplicity and Readability -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Python's syntax is clear and concise, making it easier to learn and write code. -This is crucial in robotics where complex algorithms and control logic are involved. - - -Extensive libraries for scientific computation. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Scientific computation routine are fundamental for robotics. -For example: - -- Matrix operation is needed for rigid body transformation, state estimation, and model based control. -- Optimization is needed for optimization based SLAM, optimal path planning, and optimal control. -- Visualization is needed for robot teleoperation, debugging, and simulation. - -ROS supports Python -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -`ROS`_ (Robot Operating System) is an open-source and widely used framework for robotics development. -It is designed to help developping complicated robotic applications. -ROS provides essential tools, libraries, and drivers to simplify robot programming and integration. - -Key Features of ROS: - -- Modular Architecture – Uses a node-based system where different components (nodes) communicate via messages. -- Hardware Abstraction – Supports various robots, sensors, and actuators, making development more flexible. -- Powerful Communication System – Uses topics, services, and actions for efficient data exchange between components. -- Rich Ecosystem – Offers many pre-built packages for navigation, perception, and manipulation. -- Multi-language Support – Primarily uses Python and C++, but also supports other languages. -- Simulation & Visualization – Tools like Gazebo (for simulation) and RViz (for visualization) aid in development and testing. -- Scalability & Community Support – Widely used in academia and industry, with a large open-source community. - -ROS has strong Python support (`rospy`_ for ROS1 and `rclpy`_ for ROS2). -This allows developers to easily create nodes, manage communication between -different parts of a robot system, and utilize various ROS tools. - -.. _`ROS`: https://www.ros.org/ -.. _`rospy`: http://wiki.ros.org/rospy -.. _`rclpy`: https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html - -Cross-Platform Compatibility -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Python code can run on various operating systems (Windows, macOS, Linux), providing flexibility in choosing hardware platforms for robotics projects. - -Large Community and Support -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Python has a vast and active community, offering ample resources, tutorials, and support for developers. This is invaluable when tackling challenges in robotics development. - -Situations which Python is NOT suitable for Robotics -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -We explained the advantages of Python for robotics. -However, Python is not always the best choice for robotics development. - -These are situations where Python is NOT suitable for robotics: - -High-speed real-time control -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Python is an interpreted language, which means it is slower than compiled languages like C++. -This can be a disadvantage when real-time control is required, -such as in high-speed motion control or safety-critical systems. - -So, for these applications, we recommend to understand the each algorithm you -needed using this project and implement it in other suitable languages like C++. - -Resource-constrained systems -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Python is a high-level language that requires more memory and processing power -compared to low-level languages. -So, it is difficult to run Python on resource-constrained systems like -microcontrollers or embedded devices. -In such cases, C or C++ is more suitable for these applications. diff --git a/docs/modules/1_introduction/3_technologies_for_robotics/technologies_for_robotics_main.rst b/docs/modules/1_introduction/3_technologies_for_robotics/technologies_for_robotics_main.rst deleted file mode 100644 index 0ed51e961bf..00000000000 --- a/docs/modules/1_introduction/3_technologies_for_robotics/technologies_for_robotics_main.rst +++ /dev/null @@ -1,68 +0,0 @@ -Technologies for Robotics -------------------------- - -The field of robotics needs wide areas of technologies such as mechanical engineering, -electrical engineering, computer science, and artificial intelligence (AI). -This project, `PythonRobotics`, only focus on computer science and artificial intelligence. - -The technologies for robotics are categorized as following 3 categories: - -#. `Autonomous Navigation`_ -#. `Manipulation`_ -#. `Robot type specific technologies`_ - -.. _`Autonomous Navigation`: - -Autonomous Navigation -^^^^^^^^^^^^^^^^^^^^^^^^ -Autonomous navigation is a capability that can move to a goal over long -periods of time without any external control by an operator. - -To achieve autonomous navigation, the robot needs to have the following technologies: -- It needs to know where it is (localization) -- Where it is safe (mapping) -- Where is is safe and where the robot is in the map (Simultaneous Localization and Mapping (SLAM)) -- Where and how to move (path planning) -- How to control its motion (path following). - -The autonomous system would not work correctly if any of these technologies is missing. - -In recent years, autonomous navigation technologies have received huge -attention in many fields. -For example, self-driving cars, drones, and autonomous mobile robots in indoor and outdoor environments. - -In this project, we provide many algorithms, sample codes, -and documentations for autonomous navigation. - -#. :ref:`Localization` -#. :ref:`Mapping` -#. :ref:`SLAM` -#. :ref:`Path planning` -#. :ref:`Path tracking` - - - -.. _`Manipulation`: - -Manipulation -^^^^^^^^^^^^^^^^^^^^^^^^ - -#. :ref:`Arm Navigation` - -.. _`Robot type specific technologies`: - -Robot type specific technologies -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -#. :ref:`Aerial Navigation` -#. :ref:`Bipedal` -#. :ref:`Inverted Pendulum` - - -Additional Information -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -#. :ref:`utils` -#. :ref:`Appendix` - - diff --git a/docs/modules/1_introduction/introduction_main.rst b/docs/modules/1_introduction/introduction_main.rst deleted file mode 100644 index 1871dfc3b19..00000000000 --- a/docs/modules/1_introduction/introduction_main.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _Introduction: - -Introduction -============ - -PythonRobotics is composed of two words: "Python" and "Robotics". -Therefore, I will first explain these two topics, Robotics and Python. -After that, I will provide an overview of the robotics technologies -covered in PythonRobotics. - -.. toctree:: - :maxdepth: 2 - :caption: Table of Contents - - 1_definition_of_robotics/definition_of_robotics - 2_python_for_robotics/python_for_robotics - 3_technologies_for_robotics/technologies_for_robotics - diff --git a/docs/modules/2_localization/extended_kalman_filter_localization_files/ekf_with_velocity_correction_1_0.png b/docs/modules/2_localization/extended_kalman_filter_localization_files/ekf_with_velocity_correction_1_0.png deleted file mode 100644 index 595b651bd23..00000000000 Binary files a/docs/modules/2_localization/extended_kalman_filter_localization_files/ekf_with_velocity_correction_1_0.png and /dev/null differ diff --git a/docs/modules/3_mapping/distance_map/distance_map.png b/docs/modules/3_mapping/distance_map/distance_map.png deleted file mode 100644 index 2d89252a703..00000000000 Binary files a/docs/modules/3_mapping/distance_map/distance_map.png and /dev/null differ diff --git a/docs/modules/3_mapping/distance_map/distance_map_main.rst b/docs/modules/3_mapping/distance_map/distance_map_main.rst deleted file mode 100644 index 0ef9e3022fd..00000000000 --- a/docs/modules/3_mapping/distance_map/distance_map_main.rst +++ /dev/null @@ -1,27 +0,0 @@ -Distance Map ------------- - -This is an implementation of the Distance Map algorithm for path planning. - -The Distance Map algorithm computes the unsigned distance field (UDF) and signed distance field (SDF) from a boolean field representing obstacles. - -The UDF gives the distance from each point to the nearest obstacle. The SDF gives positive distances for points outside obstacles and negative distances for points inside obstacles. - -Example -~~~~~~~ - -The algorithm is demonstrated on a simple 2D grid with obstacles: - -.. image:: distance_map.png - -API -~~~ - -.. autofunction:: Mapping.DistanceMap.distance_map.compute_sdf - -.. autofunction:: Mapping.DistanceMap.distance_map.compute_udf - -References -~~~~~~~~~~ - -- `Distance Transforms of Sampled Functions <https://cs.brown.edu/people/pfelzens/papers/dt-final.pdf>`_ paper by Pedro F. Felzenszwalb and Daniel P. Huttenlocher. \ No newline at end of file diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example.rst b/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example.rst deleted file mode 100644 index 15963aff79d..00000000000 --- a/docs/modules/4_slam/graph_slam/graphSLAM_SE2_example.rst +++ /dev/null @@ -1,208 +0,0 @@ -Graph SLAM for a real-world SE(2) dataset -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: ipython3 - - from graphslam.graph import Graph - from graphslam.load import load_g2o_se2 - -Introduction -^^^^^^^^^^^^ - -For a complete derivation of the Graph SLAM algorithm, please see -`Graph SLAM Formulation`_. - -This notebook illustrates the iterative optimization of a real-world -:math:`SE(2)` dataset. The code can be found in the ``graphslam`` -folder. For simplicity, numerical differentiation is used in lieu of -analytic Jacobians. This code originated from the -`python-graphslam <https://github.com/JeffLIrion/python-graphslam>`__ -repo, which is a full-featured Graph SLAM solver. The dataset in this -example is used with permission from Luca Carlone and was downloaded -from his `website <https://lucacarlone.mit.edu/datasets/>`__. - -The Dataset -^^^^^^^^^^^^ - -.. code:: ipython3 - - g = load_g2o_se2("data/input_INTEL.g2o") - - print("Number of edges: {}".format(len(g._edges))) - print("Number of vertices: {}".format(len(g._vertices))) - - -.. parsed-literal:: - - Number of edges: 1483 - Number of vertices: 1228 - - -.. code:: ipython3 - - g.plot(title=r"Original ($\chi^2 = {:.0f}$)".format(g.calc_chi2())) - - - -.. image:: graphSLAM_SE2_example_files/graphSLAM_SE2_example_4_0.png - - -Each edge in this dataset is a constraint that compares the measured -:math:`SE(2)` transformation between two poses to the expected -:math:`SE(2)` transformation between them, as computed using the current -pose estimates. These edges can be classified into two categories: - -1. Odometry edges constrain two consecutive vertices, and the - measurement for the :math:`SE(2)` transformation comes directly from - odometry data. -2. Scan-matching edges constrain two non-consecutive vertices. These - scan matches can be computed using, for example, 2-D LiDAR data or - landmarks; the details of how these constraints are determined is - beyond the scope of this example. This is often referred to as *loop - closure* in the Graph SLAM literature. - -We can easily parse out the two different types of edges present in this -dataset and plot them. - -.. code:: ipython3 - - def parse_edges(g): - """Split the graph `g` into two graphs, one with only odometry edges and the other with only scan-matching edges. - - Parameters - ---------- - g : graphslam.graph.Graph - The input graph - - Returns - ------- - g_odom : graphslam.graph.Graph - A graph consisting of the vertices and odometry edges from `g` - g_scan : graphslam.graph.Graph - A graph consisting of the vertices and scan-matching edges from `g` - - """ - edges_odom = [] - edges_scan = [] - - for e in g._edges: - if abs(e.vertex_ids[1] - e.vertex_ids[0]) == 1: - edges_odom.append(e) - else: - edges_scan.append(e) - - g_odom = Graph(edges_odom, g._vertices) - g_scan = Graph(edges_scan, g._vertices) - - return g_odom, g_scan - -.. code:: ipython3 - - g_odom, g_scan = parse_edges(g) - - print("Number of odometry edges: {:4d}".format(len(g_odom._edges))) - print("Number of scan-matching edges: {:4d}".format(len(g_scan._edges))) - - print("\nχ^2 error from odometry edges: {:11.3f}".format(g_odom.calc_chi2())) - print("χ^2 error from scan-matching edges: {:11.3f}".format(g_scan.calc_chi2())) - - -.. parsed-literal:: - - Number of odometry edges: 1227 - Number of scan-matching edges: 256 - - χ^2 error from odometry edges: 0.232 - χ^2 error from scan-matching edges: 7191686.151 - - -.. code:: ipython3 - - g_odom.plot(title="Odometry edges") - - - -.. image:: graphSLAM_SE2_example_files/graphSLAM_SE2_example_8_0.png - - -.. code:: ipython3 - - g_scan.plot(title="Scan-matching edges") - - - -.. image:: graphSLAM_SE2_example_files/graphSLAM_SE2_example_9_0.png - - -Optimization -^^^^^^^^^^^^ - -Initially, the pose estimates are consistent with the collected odometry -measurements, and the odometry edges contribute almost zero towards the -:math:`\chi^2` error. However, there are large discrepancies between the -scan-matching constraints and the initial pose estimates. This is not -surprising, since small errors in odometry readings that are propagated -over time can lead to large errors in the robot’s trajectory. What makes -Graph SLAM effective is that it allows incorporation of multiple -different data sources into a single optimization problem. - -.. code:: ipython3 - - g.optimize() - - -.. parsed-literal:: - - - Iteration chi^2 rel. change - --------- ----- ----------- - 0 7191686.3825 - 1 320031728.8624 43.500234 - 2 125083004.3299 -0.609154 - 3 338155.9074 -0.997297 - 4 735.1344 -0.997826 - 5 215.8405 -0.706393 - 6 215.8405 -0.000000 - - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/GraphBasedSLAM/Graph_SLAM_optimization.gif - -.. code:: ipython3 - - g.plot(title="Optimized") - - - -.. image:: graphSLAM_SE2_example_files/graphSLAM_SE2_example_13_0.png - - -.. code:: ipython3 - - print("\nχ^2 error from odometry edges: {:7.3f}".format(g_odom.calc_chi2())) - print("χ^2 error from scan-matching edges: {:7.3f}".format(g_scan.calc_chi2())) - - -.. parsed-literal:: - - - χ^2 error from odometry edges: 142.189 - χ^2 error from scan-matching edges: 73.652 - - -.. code:: ipython3 - - g_odom.plot(title="Odometry edges") - - - -.. image:: graphSLAM_SE2_example_files/graphSLAM_SE2_example_15_0.png - - -.. code:: ipython3 - - g_scan.plot(title="Scan-matching edges") - - - -.. image:: graphSLAM_SE2_example_files/graphSLAM_SE2_example_16_0.png - diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_doc.rst b/docs/modules/4_slam/graph_slam/graphSLAM_doc.rst deleted file mode 100644 index 5297604809b..00000000000 --- a/docs/modules/4_slam/graph_slam/graphSLAM_doc.rst +++ /dev/null @@ -1,554 +0,0 @@ - -Graph SLAM -~~~~~~~~~~~~ - -.. code:: ipython3 - - import copy - import math - import itertools - import numpy as np - import matplotlib.pyplot as plt - from graph_based_slam import calc_rotational_matrix, calc_jacobian, cal_observation_sigma, \ - calc_input, observation, motion_model, Edge, pi_2_pi - - %matplotlib inline - np.set_printoptions(precision=3, suppress=True) - np.random.seed(0) - -Introduction -^^^^^^^^^^^^ - -In contrast to the probabilistic approaches for solving SLAM, such as -EKF, UKF, particle filters, and so on, the graph technique formulates -the SLAM as an optimization problem. It is mostly used to solve the full -SLAM problem in an offline fashion, i.e. optimize all the poses of the -robot after the path has been traversed. However, some variants are -available that uses graph-based approaches to perform online estimation -or to solve for a subset of the poses. - -GraphSLAM uses the motion information as well as the observations of the -environment to create least square problem that can be solved using -standard optimization techniques. - -Minimal Example -^^^^^^^^^^^^^^^ - -The following example illustrates the main idea behind graphSLAM. A -simple case of a 1D robot is considered that can only move in 1 -direction. The robot is commanded to move forward with a control input -:math:`u_t=1`, however, the motion is not perfect and the measured -odometry will deviate from the true path. At each time step the robot can -observe its environment, for this simple case as well, there is only a -single landmark at coordinates :math:`x=3`. The measured observations -are the range between the robot and landmark. These measurements are -also subjected to noise. No bearing information is required since this -is a 1D problem. - -To solve this, graphSLAM creates what is called as the system -information matrix :math:`\Omega` also referred to as :math:`H` and the -information vector :math:`\xi` also known as :math:`b`. The entries are -created based on the information of the motion and the observation. - -.. code:: ipython3 - - R = 0.2 - Q = 0.2 - N = 3 - graphics_radius = 0.1 - - odom = np.empty((N,1)) - obs = np.empty((N,1)) - x_true = np.empty((N,1)) - - landmark = 3 - # Simulated readings of odometry and observations - x_true[0], odom[0], obs[0] = 0.0, 0.0, 2.9 - x_true[1], odom[1], obs[1] = 1.0, 1.5, 2.0 - x_true[2], odom[2], obs[2] = 2.0, 2.4, 1.0 - - hxDR = copy.deepcopy(odom) - # Visualization - plt.plot(landmark,0, '*k', markersize=30) - for i in range(N): - plt.plot(odom[i], 0, '.', markersize=50, alpha=0.8, color='steelblue') - plt.plot([odom[i], odom[i] + graphics_radius], - [0,0], 'r') - plt.text(odom[i], 0.02, "X_{}".format(i), fontsize=12) - plt.plot(obs[i]+odom[i],0,'.', markersize=25, color='brown') - plt.plot(x_true[i],0,'.g', markersize=20) - plt.grid() - plt.show() - - - # Defined as a function to facilitate iteration - def get_H_b(odom, obs): - """ - Create the information matrix and information vector. This implementation is - based on the concept of virtual measurement i.e. the observations of the - landmarks are converted into constraints (edges) between the nodes that - have observed this landmark. - """ - measure_constraints = {} - omegas = {} - zids = list(itertools.combinations(range(N),2)) - H = np.zeros((N,N)) - b = np.zeros((N,1)) - for (t1, t2) in zids: - x1 = odom[t1] - x2 = odom[t2] - z1 = obs[t1] - z2 = obs[t2] - - # Adding virtual measurement constraint - measure_constraints[(t1,t2)] = (x2-x1-z1+z2) - omegas[(t1,t2)] = (1 / (2*Q)) - - # populate system's information matrix and vector - H[t1,t1] += omegas[(t1,t2)] - H[t2,t2] += omegas[(t1,t2)] - H[t2,t1] -= omegas[(t1,t2)] - H[t1,t2] -= omegas[(t1,t2)] - - b[t1] += omegas[(t1,t2)] * measure_constraints[(t1,t2)] - b[t2] -= omegas[(t1,t2)] * measure_constraints[(t1,t2)] - - return H, b - - - H, b = get_H_b(odom, obs) - print("The determinant of H: ", np.linalg.det(H)) - H[0,0] += 1 # np.inf ? - print("The determinant of H after anchoring constraint: ", np.linalg.det(H)) - - for i in range(5): - H, b = get_H_b(odom, obs) - H[(0,0)] += 1 - - # Recover the posterior over the path - dx = np.linalg.inv(H) @ b - odom += dx - # repeat till convergence - print("Running graphSLAM ...") - print("Odometry values after optimzation: \n", odom) - - plt.figure() - plt.plot(x_true, np.zeros(x_true.shape), '.', markersize=20, label='Ground truth') - plt.plot(odom, np.zeros(x_true.shape), '.', markersize=20, label='Estimation') - plt.plot(hxDR, np.zeros(x_true.shape), '.', markersize=20, label='Odom') - plt.legend() - plt.grid() - plt.show() - - - -.. image:: graphSLAM_doc_files/graphSLAM_doc_2_0.png - - -.. parsed-literal:: - - The determinant of H: 0.0 - The determinant of H after anchoring constraint: 18.750000000000007 - Running graphSLAM ... - Odometry values after optimzation: - [[-0. ] - [ 0.9] - [ 1.9]] - - - -.. image:: graphSLAM_doc_files/graphSLAM_doc_2_2.png - - -In particular, the tasks are split into 2 parts, graph construction, and -graph optimization. ### Graph Construction - -Firstly the nodes are defined -:math:`\boldsymbol{x} = \boldsymbol{x}_{1:n}` such that each node is the -pose of the robot at time :math:`t_i` Secondly, the edges i.e. the -constraints, are constructed according to the following conditions: - -- robot moves from :math:`\boldsymbol{x}_i` to - :math:`\boldsymbol{x}_j`. This edge corresponds to the odometry - measurement. Relative motion constraints (Not included in the - previous minimal example). -- Measurement constraints, this can be done in two ways: - - - The information matrix is set in such a way that it includes the - landmarks in the map as well. Then the constraints can be entered - in a straightforward fashion between a node - :math:`\boldsymbol{x}_i` and some landmark :math:`m_k` - - Through creating a virtual measurement among all the node that - have observed the same landmark. More concretely, robot observes - the same landmark from :math:`\boldsymbol{x}_i` and - :math:`\boldsymbol{x}_j`. Relative measurement constraint. The - “virtual measurement” :math:`\boldsymbol{z}_{ij}`, which is the - estimated pose of :math:`\boldsymbol{x}_j` as seen from the node - :math:`\boldsymbol{x}_i`. The virtual measurement can then be - entered in the information matrix and vector in a similar fashion - to the motion constraints. - -An edge is fully characterized by the values of the error (entry to -information vector) and the local information matrix (entry to the -system’s information vector). The larger the local information matrix -(lower :math:`Q` or :math:`R`) the values that this edge will contribute -with. - -Important Notes: - -- The addition to the information matrix and vector are added to the - earlier values. -- In the case of 2D robot, the constraints will be non-linear, - therefore, a Jacobian of the error w.r.t the states is needed when - updated :math:`H` and :math:`b`. -- The anchoring constraint is needed in order to avoid having a - singular information matri. - -Graph Optimization -^^^^^^^^^^^^^^^^^^ - -The result from this formulation yields an overdetermined system of -equations. The goal after constructing the graph is to find: -:math:`x^*=\underset{x}{\mathrm{argmin}}~\underset{ij}\Sigma~f(e_{ij})`, -where :math:`f` is some error function that depends on the edges between -to related nodes :math:`i` and :math:`j`. The derivation in the references -arrive at the solution for :math:`x^* = H^{-1}b` - -Planar Example: -^^^^^^^^^^^^^^^ - -Now we will go through an example with a more realistic case of a 2D -robot with 3DoF, namely, :math:`[x, y, \theta]^T` - -.. code:: ipython3 - - # Simulation parameter - Qsim = np.diag([0.01, np.deg2rad(0.010)])**2 # error added to range and bearing - Rsim = np.diag([0.1, np.deg2rad(1.0)])**2 # error added to [v, w] - - DT = 2.0 # time tick [s] - SIM_TIME = 100.0 # simulation time [s] - MAX_RANGE = 30.0 # maximum observation range - STATE_SIZE = 3 # State size [x,y,yaw] - - # TODO: Why not use Qsim ? - # Covariance parameter of Graph Based SLAM - C_SIGMA1 = 0.1 - C_SIGMA2 = 0.1 - C_SIGMA3 = np.deg2rad(1.0) - - MAX_ITR = 20 # Maximum iteration during optimization - timesteps = 1 - - # consider only 2 landmarks for simplicity - # RFID positions [x, y, yaw] - RFID = np.array([[10.0, -2.0, 0.0], - # [15.0, 10.0, 0.0], - # [3.0, 15.0, 0.0], - # [-5.0, 20.0, 0.0], - # [-5.0, 5.0, 0.0] - ]) - - # State Vector [x y yaw v]' - xTrue = np.zeros((STATE_SIZE, 1)) - xDR = np.zeros((STATE_SIZE, 1)) # Dead reckoning - xTrue[2] = np.deg2rad(45) - xDR[2] = np.deg2rad(45) - # history initial values - hxTrue = xTrue - hxDR = xTrue - _, z, _, _ = observation(xTrue, xDR, np.array([[0,0]]).T, RFID) - hz = [z] - - for i in range(timesteps): - u = calc_input() - xTrue, z, xDR, ud = observation(xTrue, xDR, u, RFID) - hxDR = np.hstack((hxDR, xDR)) - hxTrue = np.hstack((hxTrue, xTrue)) - hz.append(z) - - # visualize - graphics_radius = 0.3 - plt.plot(RFID[:, 0], RFID[:, 1], "*k", markersize=20) - plt.plot(hxDR[0, :], hxDR[1, :], '.', markersize=50, alpha=0.8, label='Odom') - plt.plot(hxTrue[0, :], hxTrue[1, :], '.', markersize=20, alpha=0.6, label='X_true') - - for i in range(hxDR.shape[1]): - x = hxDR[0, i] - y = hxDR[1, i] - yaw = hxDR[2, i] - plt.plot([x, x + graphics_radius * np.cos(yaw)], - [y, y + graphics_radius * np.sin(yaw)], 'r') - d = hz[i][:, 0] - angle = hz[i][:, 1] - plt.plot([x + d * np.cos(angle + yaw)], [y + d * np.sin(angle + yaw)], '.', - markersize=20, alpha=0.7) - plt.legend() - plt.grid() - plt.show() - - - -.. image:: graphSLAM_doc_files/graphSLAM_doc_4_0.png - - -.. code:: ipython3 - - # Copy the data to have a consistent naming with the .py file - zlist = copy.deepcopy(hz) - x_opt = copy.deepcopy(hxDR) - xlist = copy.deepcopy(hxDR) - number_of_nodes = x_opt.shape[1] - n = number_of_nodes * STATE_SIZE - -After the data has been saved, the graph will be constructed by looking -at each pair for nodes. The virtual measurement is only created if two -nodes have observed the same landmark at different points in time. The -next cells are a walk through for a single iteration of graph -construction -> optimization -> estimate update. - -.. code:: ipython3 - - # get all the possible combination of the different node - zids = list(itertools.combinations(range(len(zlist)), 2)) - print("Node combinations: \n", zids) - - for i in range(xlist.shape[1]): - print("Node {} observed landmark with ID {}".format(i, zlist[i][0, 3])) - - -.. parsed-literal:: - - Node combinations: - [(0, 1)] - Node 0 observed landmark with ID 0.0 - Node 1 observed landmark with ID 0.0 - - -In the following code snippet the error based on the virtual measurement -between node 0 and 1 will be created. The equations for the error is as follows: -:math:`e_{ij}^x = x_j + d_j cos(\psi_j +\theta_j) - x_i - d_i cos(\psi_i + \theta_i)` - -:math:`e_{ij}^y = y_j + d_j sin(\psi_j + \theta_j) - y_i - d_i sin(\psi_i + \theta_i)` - -:math:`e_{ij}^x = \psi_j + \theta_j - \psi_i - \theta_i` - -Where :math:`[x_i, y_i, \psi_i]` is the pose for node :math:`i` and -similarly for node :math:`j`, :math:`d` is the measured distance at -nodes :math:`i` and :math:`j`, and :math:`\theta` is the measured -bearing to the landmark. The difference is visualized with the figure in -the next cell. - -In case of perfect motion and perfect measurement the error shall be -zero since :math:`x_j + d_j cos(\psi_j + \theta_j)` should equal -:math:`x_i + d_i cos(\psi_i + \theta_i)` - -.. code:: ipython3 - - # Initialize edges list - edges = [] - - # Go through all the different combinations - for (t1, t2) in zids: - x1, y1, yaw1 = xlist[0, t1], xlist[1, t1], xlist[2, t1] - x2, y2, yaw2 = xlist[0, t2], xlist[1, t2], xlist[2, t2] - - # All nodes have valid observation with ID=0, therefore, no data association condition - iz1 = 0 - iz2 = 0 - - d1 = zlist[t1][iz1, 0] - angle1, phi1 = zlist[t1][iz1, 1], zlist[t1][iz1, 2] - d2 = zlist[t2][iz2, 0] - angle2, phi2 = zlist[t2][iz2, 1], zlist[t2][iz2, 2] - - # find angle between observation and horizontal - tangle1 = pi_2_pi(yaw1 + angle1) - tangle2 = pi_2_pi(yaw2 + angle2) - - # project the observations - tmp1 = d1 * math.cos(tangle1) - tmp2 = d2 * math.cos(tangle2) - tmp3 = d1 * math.sin(tangle1) - tmp4 = d2 * math.sin(tangle2) - - edge = Edge() - print(y1,y2, tmp3, tmp4) - # calculate the error of the virtual measurement - # node 1 as seen from node 2 throught the observations 1,2 - edge.e[0, 0] = x2 - x1 - tmp1 + tmp2 - edge.e[1, 0] = y2 - y1 - tmp3 + tmp4 - edge.e[2, 0] = pi_2_pi(yaw2 - yaw1 - tangle1 + tangle2) - - edge.d1, edge.d2 = d1, d2 - edge.yaw1, edge.yaw2 = yaw1, yaw2 - edge.angle1, edge.angle2 = angle1, angle2 - edge.id1, edge.id2 = t1, t2 - - edges.append(edge) - - print("For nodes",(t1,t2)) - print("Added edge with errors: \n", edge.e) - - # Visualize measurement projections - plt.plot(RFID[0, 0], RFID[0, 1], "*k", markersize=20) - plt.plot([x1,x2],[y1,y2], '.', markersize=50, alpha=0.8) - plt.plot([x1, x1 + graphics_radius * np.cos(yaw1)], - [y1, y1 + graphics_radius * np.sin(yaw1)], 'r') - plt.plot([x2, x2 + graphics_radius * np.cos(yaw2)], - [y2, y2 + graphics_radius * np.sin(yaw2)], 'r') - - plt.plot([x1,x1+tmp1], [y1,y1], label="obs 1 x") - plt.plot([x2,x2+tmp2], [y2,y2], label="obs 2 x") - plt.plot([x1,x1], [y1,y1+tmp3], label="obs 1 y") - plt.plot([x2,x2], [y2,y2+tmp4], label="obs 2 y") - plt.plot(x1+tmp1, y1+tmp3, 'o') - plt.plot(x2+tmp2, y2+tmp4, 'o') - plt.legend() - plt.grid() - plt.show() - - -.. parsed-literal:: - - 0.0 1.427649841628278 -2.0126109674819155 -3.524048014922737 - For nodes (0, 1) - Added edge with errors: - [[-0.02 ] - [-0.084] - [ 0. ]] - - - -.. image:: graphSLAM_doc_files/graphSLAM_doc_9_1.png - - -Since the constraints equations derived before are non-linear, -linearization is needed before we can insert them into the information -matrix and information vector. Two jacobians - -:math:`A = \frac{\partial e_{ij}}{\partial \boldsymbol{x}_i}` as -:math:`\boldsymbol{x}_i` holds the three variabls x, y, and theta. -Similarly, :math:`B = \frac{\partial e_{ij}}{\partial \boldsymbol{x}_j}` - -.. code:: ipython3 - - # Initialize the system information matrix and information vector - H = np.zeros((n, n)) - b = np.zeros((n, 1)) - x_opt = copy.deepcopy(hxDR) - - for edge in edges: - id1 = edge.id1 * STATE_SIZE - id2 = edge.id2 * STATE_SIZE - - t1 = edge.yaw1 + edge.angle1 - A = np.array([[-1.0, 0, edge.d1 * math.sin(t1)], - [0, -1.0, -edge.d1 * math.cos(t1)], - [0, 0, -1.0]]) - - t2 = edge.yaw2 + edge.angle2 - B = np.array([[1.0, 0, -edge.d2 * math.sin(t2)], - [0, 1.0, edge.d2 * math.cos(t2)], - [0, 0, 1.0]]) - - # TODO: use Qsim instead of sigma - sigma = np.diag([C_SIGMA1, C_SIGMA2, C_SIGMA3]) - Rt1 = calc_rotational_matrix(tangle1) - Rt2 = calc_rotational_matrix(tangle2) - edge.omega = np.linalg.inv(Rt1 @ sigma @ Rt1.T + Rt2 @ sigma @ Rt2.T) - - # Fill in entries in H and b - H[id1:id1 + STATE_SIZE, id1:id1 + STATE_SIZE] += A.T @ edge.omega @ A - H[id1:id1 + STATE_SIZE, id2:id2 + STATE_SIZE] += A.T @ edge.omega @ B - H[id2:id2 + STATE_SIZE, id1:id1 + STATE_SIZE] += B.T @ edge.omega @ A - H[id2:id2 + STATE_SIZE, id2:id2 + STATE_SIZE] += B.T @ edge.omega @ B - - b[id1:id1 + STATE_SIZE] += (A.T @ edge.omega @ edge.e) - b[id2:id2 + STATE_SIZE] += (B.T @ edge.omega @ edge.e) - - - print("The determinant of H: ", np.linalg.det(H)) - plt.figure() - plt.subplot(1,2,1) - plt.imshow(H, extent=[0, n, 0, n]) - plt.subplot(1,2,2) - plt.imshow(b, extent=[0, 1, 0, n]) - plt.show() - - # Fix the origin, multiply by large number gives same results but better visualization - H[0:STATE_SIZE, 0:STATE_SIZE] += np.identity(STATE_SIZE) - print("The determinant of H after origin constraint: ", np.linalg.det(H)) - plt.figure() - plt.subplot(1,2,1) - plt.imshow(H, extent=[0, n, 0, n]) - plt.subplot(1,2,2) - plt.imshow(b, extent=[0, 1, 0, n]) - plt.show() - - -.. parsed-literal:: - - The determinant of H: 0.0 - The determinant of H after origin constraint: 716.1972439134893 - - - -.. image:: graphSLAM_doc_files/graphSLAM_doc_11_1.png - -.. image:: graphSLAM_doc_files/graphSLAM_doc_11_2.png - -.. code:: ipython3 - - # Find the solution (first iteration) - dx = - np.linalg.inv(H) @ b - for i in range(number_of_nodes): - x_opt[0:3, i] += dx[i * 3:i * 3 + 3, 0] - print("dx: \n",dx) - print("ground truth: \n ",hxTrue) - print("Odom: \n", hxDR) - print("SLAM: \n", x_opt) - - # performance will improve with more iterations, nodes and landmarks. - print("\ngraphSLAM localization error: ", np.sum((x_opt - hxTrue) ** 2)) - print("Odom localization error: ", np.sum((hxDR - hxTrue) ** 2)) - - -.. parsed-literal:: - - dx: - [[-0. ] - [-0. ] - [ 0. ] - [ 0.02 ] - [ 0.084] - [-0. ]] - ground truth: - [[0. 1.414] - [0. 1.414] - [0.785 0.985]] - Odom: - [[0. 1.428] - [0. 1.428] - [0.785 0.976]] - SLAM: - [[-0. 1.448] - [-0. 1.512] - [ 0.785 0.976]] - - graphSLAM localization error: 0.010729072751057656 - Odom localization error: 0.0004460978857535104 - - -The references: -^^^^^^^^^^^^^^^ - -- `The GraphSLAM Algorithm with Applications to Large-Scale Mapping of Urban Structures <http://robots.stanford.edu/papers/thrun.graphslam.pdf>`_ - -- `Introduction to Mobile Robotics Graph-Based SLAM <http://ais.informatik.uni-freiburg.de/teaching/ss13/robotics/slides/16-graph-slam.pdf>`_ - -- `A Tutorial on Graph-Based SLAM <http://www2.informatik.uni-freiburg.de/~stachnis/pdf/grisetti10titsmag.pdf>`_ - -N.B. An additional step is required that uses the estimated path to -update the belief regarding the map. - diff --git a/docs/modules/4_slam/graph_slam/graphSLAM_formulation.rst b/docs/modules/4_slam/graph_slam/graphSLAM_formulation.rst deleted file mode 100644 index 4978596c102..00000000000 --- a/docs/modules/4_slam/graph_slam/graphSLAM_formulation.rst +++ /dev/null @@ -1,218 +0,0 @@ -.. _Graph SLAM Formulation: - -Graph SLAM Formulation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Author Jeff Irion - -Problem Formulation -^^^^^^^^^^^^^^^^^^^ - -Let a robot’s trajectory through its environment be represented by a -sequence of :math:`N` poses: -:math:`\mathbf{p}_1, \mathbf{p}_2, \ldots, \mathbf{p}_N`. Each pose lies -on a manifold: :math:`\mathbf{p}_i \in \mathcal{M}`. Simple examples of -manifolds used in Graph SLAM include 1-D, 2-D, and 3-D space, i.e., -:math:`\mathbb{R}`, :math:`\mathbb{R}^2`, and :math:`\mathbb{R}^3`. -These environments are *rectilinear*, meaning that there is no concept -of orientation. By contrast, in :math:`SE(2)` problem settings a robot’s -pose consists of its location in :math:`\mathbb{R}^2` and its -orientation :math:`\theta`. Similarly, in :math:`SE(3)` a robot’s pose -consists of its location in :math:`\mathbb{R}^3` and its orientation, -which can be represented via Euler angles, quaternions, or :math:`SO(3)` -rotation matrices. - -As the robot explores its environment, it collects a set of :math:`M` -measurements :math:`\mathcal{Z} = \{\mathbf{z}_j\}`. Examples of such -measurements include odometry, GPS, and IMU data. Given a set of poses -:math:`\mathbf{p}_1, \ldots, \mathbf{p}_N`, we can compute the estimated -measurement -:math:`\hat{\mathbf{z}}_j(\mathbf{p}_1, \ldots, \mathbf{p}_N)`. We can -then compute the *residual* -:math:`\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j)` for measurement -:math:`j`. The formula for the residual depends on the type of -measurement. As an example, let :math:`\mathbf{z}_1` be an odometry -measurement that was collected when the robot traveled from -:math:`\mathbf{p}_1` to :math:`\mathbf{p}_2`. The expected measurement -and the residual are computed as - -.. math:: - - \begin{aligned} - \hat{\mathbf{z}}_1(\mathbf{p}_1, \mathbf{p}_2) &= \mathbf{p}_2 \ominus \mathbf{p}_1 \\ - \mathbf{e}_1(\mathbf{z}_1, \hat{\mathbf{z}}_1) &= \mathbf{z}_1 \ominus \hat{\mathbf{z}}_1 = \mathbf{z}_1 \ominus (\mathbf{p}_2 \ominus \mathbf{p}_1),\end{aligned} - -where the :math:`\ominus` operator indicates inverse pose composition. -We model measurement :math:`\mathbf{z}_j` as having independent Gaussian -noise with zero mean and covariance matrix :math:`\Omega_j^{-1}`; we -refer to :math:`\Omega_j` as the *information matrix* for measurement -:math:`j`. That is, - -.. math:: - p(\mathbf{z}_j \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) = \eta_j \exp (-\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\mathsf{T}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j) - :label: infomat - -where :math:`\eta_j` is the normalization constant. - -The objective of Graph SLAM is to find the maximum likelihood set of -poses given the measurements :math:`\mathcal{Z} = \{\mathbf{z}_j\}`; in -other words, we want to find - -.. math:: \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \ p(\mathbf{p}_1, \ldots, \mathbf{p}_N \ | \ \mathcal{Z}) - -Using Bayes’ rule, we can write this probability as - -.. math:: - \begin{aligned} - p(\mathbf{p}_1, \ldots, \mathbf{p}_N \ | \ \mathcal{Z}) &= \frac{p( \mathcal{Z} \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) p(\mathbf{p}_1, \ldots, \mathbf{p}_N) }{ p(\mathcal{Z}) } \notag \\ - &\propto p( \mathcal{Z} \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) - \end{aligned} - :label: bayes - -since :math:`p(\mathcal{Z})` is a constant (albeit, an unknown constant) -and we assume that :math:`p(\mathbf{p}_1, \ldots, \mathbf{p}_N)` is -uniformly distributed. Therefore, we -can use Eq. :eq:`infomat` and and Eq. :eq:`bayes` to simplify the Graph SLAM -optimization as follows: - -.. math:: - - \begin{aligned} - \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \ p(\mathbf{p}_1, \ldots, \mathbf{p}_N \ | \ \mathcal{Z}) &= \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \ p( \mathcal{Z} \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) \\ - &= \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \prod_{j=1}^M p(\mathbf{z}_j \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) \\ - &= \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \prod_{j=1}^M \exp \left( -(\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j) \right) \\ - &= \mathop{\mathrm{arg\,min}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \sum_{j=1}^M (\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j).\end{aligned} - -We define - -.. math:: \chi^2 := \sum_{j=1}^M (\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j), - -and this is what we seek to minimize. - -Dimensionality and Pose Representation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Before proceeding further, it is helpful to discuss the dimensionality -of the problem. We have: - -- A set of :math:`N` poses - :math:`\mathbf{p}_1, \mathbf{p}_2, \ldots, \mathbf{p}_N`, where each - pose lies on the manifold :math:`\mathcal{M}` - - - Each pose :math:`\mathbf{p}_i` is represented as a vector in (a - subset of) :math:`\mathbb{R}^d`. For example: - - - An :math:`SE(2)` pose is typically represented as - :math:`(x, y, \theta)`, and thus :math:`d = 3`. - - - An :math:`SE(3)` pose is typically represented as - :math:`(x, y, z, q_x, q_y, q_z, q_w)`, where :math:`(x, y, z)` - is a point in :math:`\mathbb{R}^3` and - :math:`(q_x, q_y, q_z, q_w)` is a *quaternion*, and so - :math:`d = 7`. For more information about :math:`SE(3)` - parameterization and pose transformations, see - [blanco2010tutorial]_. - - - We also need to be able to represent each pose compactly as a - vector in (a subset of) :math:`\mathbb{R}^c`. - - - Since an :math:`SE(2)` pose has three degrees of freedom, the - :math:`(x, y, \theta)` representation is again sufficient and - :math:`c=3`. - - - An :math:`SE(3)` pose only has six degrees of freedom, and we - can represent it compactly as :math:`(x, y, z, q_x, q_y, q_z)`, - and thus :math:`c=6`. - - - We use the :math:`\boxplus` operator to indicate pose composition - when one or both of the poses are represented compactly. The - output can be a pose in :math:`\mathcal{M}` or a vector in - :math:`\mathbb{R}^c`, as required by context. - -- A set of :math:`M` measurements - :math:`\mathcal{Z} = \{\mathbf{z}_1, \mathbf{z}_2, \ldots, \mathbf{z}_M\}` - - - Each measurement’s dimensionality can be unique, and we will use - :math:`\bullet` to denote a “wildcard” variable. - - - Measurement :math:`\mathbf{z}_j \in \mathbb{R}^\bullet` has an - associated information matrix - :math:`\Omega_j \in \mathbb{R}^{\bullet \times \bullet}` and - residual function - :math:`\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j) = \mathbf{e}_j(\mathbf{z}_j, \mathbf{p}_1, \ldots, \mathbf{p}_N) \in \mathbb{R}^\bullet`. - - - A measurement could, in theory, constrain anywhere from 1 pose to - all :math:`N` poses. In practice, each measurement usually - constrains only 1 or 2 poses. - -Graph SLAM Algorithm -^^^^^^^^^^^^^^^^^^^^ - -The “Graph” in Graph SLAM refers to the fact that we view the problem as -a graph. The graph has a set :math:`\mathcal{V}` of :math:`N` vertices, -where each vertex :math:`v_i` has an associated pose -:math:`\mathbf{p}_i`. Similarly, the graph has a set :math:`\mathcal{E}` -of :math:`M` edges, where each edge :math:`e_j` has an associated -measurement :math:`\mathbf{z}_j`. In practice, the edges in this graph -are either unary (i.e., a loop) or binary. (Note: :math:`e_j` refers to -the edge in the graph associated with measurement :math:`\mathbf{z}_j`, -whereas :math:`\mathbf{e}_j` refers to the residual function associated -with :math:`\mathbf{z}_j`.) For more information about the Graph SLAM -algorithm, see [grisetti2010tutorial]_. - -We want to optimize - -.. math:: \chi^2 = \sum_{e_j \in \mathcal{E}} \mathbf{e}_j^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j. - -Let :math:`\mathbf{x}_i \in \mathbb{R}^c` be the compact representation -of pose :math:`\mathbf{p}_i \in \mathcal{M}`, and let - -.. math:: \mathbf{x} := \begin{bmatrix} \mathbf{x}_1 \\ \mathbf{x}_2 \\ \vdots \\ \mathbf{x}_N \end{bmatrix} \in \mathbb{R}^{cN} - -We will solve this optimization problem iteratively. Let - -.. math:: \mathbf{x}^{k+1} := \mathbf{x}^k \boxplus \Delta \mathbf{x}^k = \begin{bmatrix} \mathbf{x}_1 \boxplus \Delta \mathbf{x}_1 \\ \mathbf{x}_2 \boxplus \Delta \mathbf{x}_2 \\ \vdots \\ \mathbf{x}_N \boxplus \Delta \mathbf{x}_2 \end{bmatrix} - :label: update - -The :math:`\chi^2` error at iteration :math:`k+1` is - -.. math:: \chi_{k+1}^2 = \sum_{e_j \in \mathcal{E}} \underbrace{\left[ \mathbf{e}_j(\mathbf{x}^{k+1}) \right]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\mathbf{e}_j(\mathbf{x}^{k+1})}_{\bullet \times 1}. - :label: chisq_at_kplusone - -We will linearize the residuals as: - -.. math:: - \begin{aligned} - \mathbf{e}_j(\mathbf{x}^{k+1}) &= \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k) \\ - &\approx \mathbf{e}_j(\mathbf{x}^{k}) + \frac{\partial}{\partial \Delta \mathbf{x}^k} \left[ \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k) \right] \Delta \mathbf{x}^k \\ - &= \mathbf{e}_j(\mathbf{x}^{k}) + \left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right) \frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k} \Delta \mathbf{x}^k. - \end{aligned} - :label: linearization - -Plugging :eq:`linearization` into :eq:`chisq_at_kplusone`, we get: - -.. math:: - - \begin{aligned} - \chi_{k+1}^2 &\approx \ \ \ \ \ \sum_{e_j \in \mathcal{E}} \underbrace{[ \mathbf{e}_j(\mathbf{x}^k)]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\mathbf{e}_j(\mathbf{x}^k)}_{\bullet \times 1} \notag \\ - &\hphantom{\approx} \ \ \ + \sum_{e_j \in \mathcal{E}} \underbrace{[ \mathbf{e}_j(\mathbf{x^k}) ]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN} \underbrace{\Delta \mathbf{x}^k}_{cN \times 1} \notag \\ - &\hphantom{\approx} \ \ \ + \sum_{e_j \in \mathcal{E}} \underbrace{(\Delta \mathbf{x}^k)^{\scriptstyle{\mathsf{T}}}}_{1 \times cN} \underbrace{ \left( \frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k} \right)^{\scriptstyle{\mathsf{T}}}}_{cN \times dN} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)^{\scriptstyle{\mathsf{T}}}}_{dN \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN} \underbrace{\Delta \mathbf{x}^k}_{cN \times 1} \notag \\ - &= \chi_k^2 + 2 \mathbf{b}^{\scriptstyle{\mathsf{T}}}\Delta \mathbf{x}^k + (\Delta \mathbf{x}^k)^{\scriptstyle{\mathsf{T}}}H \Delta \mathbf{x}^k, \notag\end{aligned} - -where - -.. math:: - - \begin{aligned} - \mathbf{b}^{\scriptstyle{\mathsf{T}}}&= \sum_{e_j \in \mathcal{E}} \underbrace{[ \mathbf{e}_j(\mathbf{x^k}) ]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN} \\ - H &= \sum_{e_j \in \mathcal{E}} \underbrace{ \left( \frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k} \right)^{\scriptstyle{\mathsf{T}}}}_{cN \times dN} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)^{\scriptstyle{\mathsf{T}}}}_{dN \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN}.\end{aligned} - -Using this notation, we obtain the optimal update as - -.. math:: \Delta \mathbf{x}^k = -H^{-1} \mathbf{b}. \label{eq:deltax} - -We apply this update to the poses via :eq:`update` and repeat until convergence. - - -.. [blanco2010tutorial] Blanco, J.-L.A tutorial onSE(3) transformation parameterization and on-manifold optimization.University of Malaga, Tech. Rep 3(2010) -.. [grisetti2010tutorial] Grisetti, G., Kummerle, R., Stachniss, C., and Burgard, W.A tutorial on graph-based SLAM.IEEE Intelligent Transportation Systems Magazine 2, 4 (2010), 31–43. - diff --git a/docs/modules/4_slam/slam_main.rst b/docs/modules/4_slam/slam_main.rst deleted file mode 100644 index 98211986c2b..00000000000 --- a/docs/modules/4_slam/slam_main.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _`SLAM`: - -SLAM -==== - -Simultaneous Localization and Mapping(SLAM) examples -Simultaneous Localization and Mapping (SLAM) is an ability to estimate the pose of a robot and the map of the environment at the same time. The SLAM problem is hard to -solve, because a map is needed for localization and localization is needed for mapping. In this way, SLAM is often said to be similar to a ‘chicken-and-egg’ problem. Popular SLAM solution methods include the extended Kalman filter, particle filter, and Fast SLAM algorithm[31]. Fig.4 shows SLAM simulation results using extended Kalman filter and results using FastSLAM2.0[31]. - -.. toctree:: - :maxdepth: 2 - :caption: Contents - - iterative_closest_point_matching/iterative_closest_point_matching - ekf_slam/ekf_slam - FastSLAM1/FastSLAM1 - FastSLAM2/FastSLAM2 - graph_slam/graph_slam diff --git a/docs/modules/5_path_planning/catmull_rom_spline/blending_functions.png b/docs/modules/5_path_planning/catmull_rom_spline/blending_functions.png deleted file mode 100644 index 928946df46c..00000000000 Binary files a/docs/modules/5_path_planning/catmull_rom_spline/blending_functions.png and /dev/null differ diff --git a/docs/modules/5_path_planning/catmull_rom_spline/catmull_rom_path_planning.png b/docs/modules/5_path_planning/catmull_rom_spline/catmull_rom_path_planning.png deleted file mode 100644 index 1d0ff001e60..00000000000 Binary files a/docs/modules/5_path_planning/catmull_rom_spline/catmull_rom_path_planning.png and /dev/null differ diff --git a/docs/modules/5_path_planning/catmull_rom_spline/catmull_rom_spline_main.rst b/docs/modules/5_path_planning/catmull_rom_spline/catmull_rom_spline_main.rst deleted file mode 100644 index 72e558c486e..00000000000 --- a/docs/modules/5_path_planning/catmull_rom_spline/catmull_rom_spline_main.rst +++ /dev/null @@ -1,103 +0,0 @@ -Catmull-Rom Spline Planning ----------------------------- - -.. image:: catmull_rom_path_planning.png - -This is a Catmull-Rom spline path planning routine. - -If you provide waypoints, the Catmull-Rom spline generates a smooth path that always passes through the control points, -exhibits local control, and maintains 𝐶1 continuity. - - -Catmull-Rom Spline Fundamentals -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Catmull-Rom splines are a type of cubic spline that passes through a given set of points, known as control points. - -They are defined by the following equation for calculating a point on the spline: - -:math:`P(t) = 0.5 \times \left( 2P_1 + (-P_0 + P_2)t + (2P_0 - 5P_1 + 4P_2 - P_3)t^2 + (-P_0 + 3P_1 - 3P_2 + P_3)t^3 \right)` - -Where: - -* :math:`P(t)` is the point on the spline at parameter :math:`t`. -* :math:`P_0, P_1, P_2, P_3` are the control points surrounding the parameter :math:`t`. - -Types of Catmull-Rom Splines -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are different types of Catmull-Rom splines based on the choice of the **tau** parameter, which influences how the curve -behaves in relation to the control points: - -1. **Uniform Catmull-Rom Spline**: - The standard implementation where the parameterization is uniform. Each segment of the spline is treated equally, - regardless of the distances between control points. - - -2. **Chordal Catmull-Rom Spline**: - This spline type takes into account the distance between control points. The parameterization is based on the actual distance - along the spline, ensuring smoother transitions. The equation can be modified to include the chord length :math:`L_i` between - points :math:`P_i` and :math:`P_{i+1}`: - - .. math:: - \tau_i = \sqrt{(x_{i+1} - x_i)^2 + (y_{i+1} - y_i)^2} - -3. **Centripetal Catmull-Rom Spline**: - This variation improves upon the chordal spline by using the square root of the distance to determine the parameterization, - which avoids oscillations and creates a more natural curve. The parameter :math:`t_i` is adjusted using the following relation: - - .. math:: - t_i = \sqrt{(x_{i+1} - x_i)^2 + (y_{i+1} - y_i)^2} - - -Blending Functions -~~~~~~~~~~~~~~~~~~~~~ - -In Catmull-Rom spline interpolation, blending functions are used to calculate the influence of each control point on the spline at a -given parameter :math:`t`. The blending functions ensure that the spline is smooth and passes through the control points while -maintaining continuity. The four blending functions used in Catmull-Rom splines are defined as follows: - -1. **Blending Function 1**: - - .. math:: - b_1(t) = -t + 2t^2 - t^3 - -2. **Blending Function 2**: - - .. math:: - b_2(t) = 2 - 5t^2 + 3t^3 - -3. **Blending Function 3**: - - .. math:: - b_3(t) = t + 4t^2 - 3t^3 - -4. **Blending Function 4**: - - .. math:: - b_4(t) = -t^2 + t^3 - -The blending functions are combined in the spline equation to create a smooth curve that reflects the influence of each control point. - -The following figure illustrates the blending functions over the interval :math:`[0, 1]`: - -.. image:: blending_functions.png - -Catmull-Rom Spline API -~~~~~~~~~~~~~~~~~~~~~~~ - -This section provides an overview of the functions used for Catmull-Rom spline path planning. - -API -++++ - -.. autofunction:: PathPlanning.Catmull_RomSplinePath.catmull_rom_spline_path.catmull_rom_point - -.. autofunction:: PathPlanning.Catmull_RomSplinePath.catmull_rom_spline_path.catmull_rom_spline - - -References -~~~~~~~~~~~~~~ - -- `Catmull-Rom Spline - Wikipedia <https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline>`__ -- `Catmull-Rom Splines <http://graphics.cs.cmu.edu/nsp/course/15-462/Fall04/assts/catmullRom.pdf>`__ \ No newline at end of file diff --git a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_1.png b/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_1.png deleted file mode 100644 index 9b0334a6651..00000000000 Binary files a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_1.png and /dev/null differ diff --git a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_3.png b/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_3.png deleted file mode 100644 index 8b746e00a0d..00000000000 Binary files a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_3.png and /dev/null differ diff --git a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_4.png b/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_4.png deleted file mode 100644 index 2c9d8292278..00000000000 Binary files a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_4.png and /dev/null differ diff --git a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_5.png b/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_5.png deleted file mode 100644 index eb2021e40c9..00000000000 Binary files a/docs/modules/5_path_planning/closed_loop_rrt_star_car/Figure_5.png and /dev/null differ diff --git a/docs/modules/5_path_planning/elastic_bands/elastic_bands_main.rst b/docs/modules/5_path_planning/elastic_bands/elastic_bands_main.rst deleted file mode 100644 index 8a3e517105b..00000000000 --- a/docs/modules/5_path_planning/elastic_bands/elastic_bands_main.rst +++ /dev/null @@ -1,74 +0,0 @@ -Elastic Bands -------------- - -This is a path planning with Elastic Bands. - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ElasticBands/animation.gif - - -Core Concept -~~~~~~~~~~~~ -- **Elastic Band**: A dynamically deformable collision-free path initialized by a global planner. -- **Objective**: - - * Shorten and smooth the path. - * Maximize obstacle clearance. - * Maintain global path connectivity. - -Bubble Representation -~~~~~~~~~~~~~~~~~~~~~~~~ -- **Definition**: A local free-space region around configuration :math:`b`: - - .. math:: - B(b) = \{ q: \|q - b\| < \rho(b) \}, - - where :math:`\rho(b)` is the radius of the bubble. - - -Force-Based Deformation -~~~~~~~~~~~~~~~~~~~~~~~ -The elastic band deforms under artificial forces: - -Internal Contraction Force -++++++++++++++++++++++++++ -- **Purpose**: Reduces path slack and length. -- **Formula**: For node :math:`b_i`: - - .. math:: - f_c(b_i) = k_c \left( \frac{b_{i-1} - b_i}{\|b_{i-1} - b_i\|} + \frac{b_{i+1} - b_i}{\|b_{i+1} - b_i\|} \right) - - where :math:`k_c` is the contraction gain. - -External Repulsion Force -+++++++++++++++++++++++++ -- **Purpose**: Pushes the path away from obstacles. -- **Formula**: For node :math:`b_i`: - - .. math:: - f_r(b_i) = \begin{cases} - k_r (\rho_0 - \rho(b_i)) \nabla \rho(b_i) & \text{if } \rho(b_i) < \rho_0, \\ - 0 & \text{otherwise}. - \end{cases} - - where :math:`k_r` is the repulsion gain, :math:`\rho_0` is the maximum distance for applying repulsion force, and :math:`\nabla \rho(b_i)` is approximated via finite differences: - - .. math:: - \frac{\partial \rho}{\partial x} \approx \frac{\rho(b_i + h) - \rho(b_i - h)}{2h}. - -Dynamic Path Maintenance -~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. **Node Update**: - - .. math:: - b_i^{\text{new}} = b_i^{\text{old}} + \alpha (f_c + f_r), - - where :math:`\alpha` is a step-size parameter, which often proportional to :math:`\rho(b_i^{\text{old}})` - -2. **Overlap Enforcement**: -- Insert new nodes if adjacent nodes are too far apart -- Remove redundant nodes if adjacent nodes are too close - -References -~~~~~~~~~~~~~~~~~~~~~~~ - -- `Elastic Bands: Connecting Path Planning and Control <http://www8.cs.umu.se/research/ifor/dl/Control/elastic%20bands.pdf>`__ diff --git a/docs/modules/5_path_planning/frenet_frame_path/frenet_frame_path_main.rst b/docs/modules/5_path_planning/frenet_frame_path/frenet_frame_path_main.rst deleted file mode 100644 index 38efaf2b53a..00000000000 --- a/docs/modules/5_path_planning/frenet_frame_path/frenet_frame_path_main.rst +++ /dev/null @@ -1,46 +0,0 @@ -Optimal Trajectory in a Frenet Frame ------------------------------------- - -This is optimal trajectory generation in a Frenet Frame. - -The cyan line is the target course and black crosses are obstacles. - -The red line is predicted path. - -High Speed and Velocity Keeping Scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/high_speed_and_velocity_keeping_frenet_path.gif - -This scenario shows how the trajectory is maintained at high speeds while keeping a consistent velocity. - -High Speed and Merging and Stopping Scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/high_speed_and_merging_and_stopping_frenet_path.gif - -This scenario demonstrates the trajectory planning at high speeds with merging and stopping behaviors. - -Low Speed and Velocity Keeping Scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/low_speed_and_velocity_keeping_frenet_path.gif - -This scenario demonstrates how the trajectory is managed at low speeds while maintaining a steady velocity. - -Low Speed and Merging and Stopping Scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/low_speed_and_merging_and_stopping_frenet_path.gif - -This scenario illustrates the trajectory planning at low speeds with merging and stopping behaviors. - -Ref: - -- `Optimal Trajectory Generation for Dynamic Street Scenarios in a - Frenet - Frame <https://www.researchgate.net/profile/Moritz_Werling/publication/224156269_Optimal_Trajectory_Generation_for_Dynamic_Street_Scenarios_in_a_Frenet_Frame/links/54f749df0cf210398e9277af.pdf>`__ - -- `Optimal trajectory generation for dynamic street scenarios in a - Frenet Frame <https://www.youtube.com/watch?v=Cj6tAQe7UCY>`__ - diff --git a/docs/modules/5_path_planning/reeds_shepp_path/LR_L.png b/docs/modules/5_path_planning/reeds_shepp_path/LR_L.png deleted file mode 100644 index 1e64da57f2a..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/LR_L.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/LR_LR.png b/docs/modules/5_path_planning/reeds_shepp_path/LR_LR.png deleted file mode 100644 index e2c9883d8e3..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/LR_LR.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/LSL.png b/docs/modules/5_path_planning/reeds_shepp_path/LSL.png deleted file mode 100644 index 6785ad3f8cd..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/LSL.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/LSL90xR.png b/docs/modules/5_path_planning/reeds_shepp_path/LSL90xR.png deleted file mode 100644 index 54e892ba46f..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/LSL90xR.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/LSR.png b/docs/modules/5_path_planning/reeds_shepp_path/LSR.png deleted file mode 100644 index 8acc0de69fb..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/LSR.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/LSR90_L.png b/docs/modules/5_path_planning/reeds_shepp_path/LSR90_L.png deleted file mode 100644 index 58d381010d6..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/LSR90_L.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/L_R90SL.png b/docs/modules/5_path_planning/reeds_shepp_path/L_R90SL.png deleted file mode 100644 index c305c0be6ed..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/L_R90SL.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/L_R90SL90_R.png b/docs/modules/5_path_planning/reeds_shepp_path/L_R90SL90_R.png deleted file mode 100644 index f2b38329da3..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/L_R90SL90_R.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/L_R90SR.png b/docs/modules/5_path_planning/reeds_shepp_path/L_R90SR.png deleted file mode 100644 index 4323a9fe3b9..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/L_R90SR.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/L_RL.png b/docs/modules/5_path_planning/reeds_shepp_path/L_RL.png deleted file mode 100644 index ad58b8ffea2..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/L_RL.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/L_RL_R.png b/docs/modules/5_path_planning/reeds_shepp_path/L_RL_R.png deleted file mode 100644 index db4aaf6af3d..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/L_RL_R.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/L_R_L.png b/docs/modules/5_path_planning/reeds_shepp_path/L_R_L.png deleted file mode 100644 index 0d3082aeaf3..00000000000 Binary files a/docs/modules/5_path_planning/reeds_shepp_path/L_R_L.png and /dev/null differ diff --git a/docs/modules/5_path_planning/reeds_shepp_path/reeds_shepp_path_main.rst b/docs/modules/5_path_planning/reeds_shepp_path/reeds_shepp_path_main.rst deleted file mode 100644 index ff377eb91b5..00000000000 --- a/docs/modules/5_path_planning/reeds_shepp_path/reeds_shepp_path_main.rst +++ /dev/null @@ -1,392 +0,0 @@ -Reeds Shepp planning --------------------- - -A sample code with Reeds Shepp path planning. - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ReedsSheppPath/animation.gif?raw=true - -Mathematical Description of Individual Path Types -================================================= -Here is an overview of mathematical derivations of formulae for individual path types. - -In all the derivations below, radius of curvature of the vehicle is assumed to be of unit length and start pose is considered to be at origin. (*In code we are removing the offset due to start position and normalising the lengths before passing the values to these functions.*) - -Also, (t, u, v) respresent the measure of each motion requried. Thus, in case of a turning maneuver, they represent the angle inscribed at the centre of turning circle and in case of straight maneuver, they represent the distance to be travelled. - -1. **Left-Straight-Left** - -.. image:: LSL.png - -We can deduce the following facts using geometry. - -- AGHC is a rectangle. -- :math:`∠LAC = ∠BAG = t` -- :math:`t + v = φ` -- :math:`C(x - sin(φ), y + cos(φ))` -- :math:`A(0, 1)` -- :math:`u, t = polar(vector<AC>)` - -Hence, we have: - -- :math:`u, t = polar(x - sin(φ), y + cos(φ) - 1)` -- :math:`v = φ - t` - - -2. **Left-Straight-Right** - -.. image:: LSR.png - -With followng notations: - -- :math:`∠MBD = t1` -- :math:`∠BDF = θ` -- :math:`BC = u1` - -We can deduce the following facts using geometry. - -- D is mid-point of BC and FG. -- :math:`t - v = φ` -- :math:`C(x + sin(φ), y - cos(φ))` -- :math:`A(0, 1)` -- :math:`u1, t1 = polar(vector<AC>)` -- :math:`\frac{u1^2}{4} = 1 + \frac{u^2}{4}` -- :math:`BF = 1` [Radius Of Curvature] -- :math:`FD = \frac{u}{2}` -- :math:`θ = arctan(\frac{BF}{FD})` -- :math:`t1 + θ = t` - -Hence, we have: - -- :math:`u1, t1 = polar(x + sin(φ), y - cos(φ) - 1)` -- :math:`u = \sqrt{u1^2 - 4}` -- :math:`θ = arctan(\frac{2}{u})` -- :math:`t = t1 + θ` -- :math:`v = t - φ` - -3. **LeftxRightxLeft** - -.. image:: L_R_L.png - -With followng notations: - -- :math:`∠CBD = ∠CDB = A` [BCD is an isoceles triangle] -- :math:`∠DBK = θ` -- :math:`BD = u1` - -We can deduce the following facts using geometry. - -- :math:`t + u + v = φ` -- :math:`D(x - sin(φ), y + cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BD>)` -- :math:`A = arccos(\frac{BD/2}{CD})` -- :math:`u = (π - 2*A)` -- :math:`∠ABK = \frac{π}{2}` -- :math:`∠KBD = θ` -- :math:`t = ∠ABK + ∠KBD + ∠DBC` - -Hence, we have: - -- :math:`u1, θ = polar(x - sin(φ), y + cos(φ) - 1)` -- :math:`A = arccos(\frac{u1/2}{2})` -- :math:`t = \frac{π}{2} + θ + A` -- :math:`u = (π - 2*A)` -- :math:`v = (φ - t - u)` - -4. **LeftxRight-Left** - -.. image:: L_RL.png - -With followng notations: - -- :math:`∠CBD = ∠CDB = A` [BCD is an isoceles triangle] -- :math:`∠DBK = θ` -- :math:`BD = u1` - -We can deduce the following facts using geometry. - -- :math:`t + u - v = φ` -- :math:`D(x - sin(φ), y + cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BD>)` -- :math:`A = arccos(\frac{BD/2}{CD})` -- :math:`u = (π - 2*A)` -- :math:`∠ABK = \frac{π}{2}` -- :math:`∠KBD = θ` -- :math:`t = ∠ABK + ∠KBD + ∠DBC` - -Hence, we have: - -- :math:`u1, θ = polar(x - sin(φ), y + cos(φ) - 1)` -- :math:`A = arccos(\frac{u1/2}{2})` -- :math:`t = \frac{π}{2} + θ + A` -- :math:`u = (π - 2*A)` -- :math:`v = (-φ + t + u)` - -5. **Left-RightxLeft** - -.. image:: LR_L.png - -With followng notations: - -- :math:`∠CBD = ∠CDB = A` [BCD is an isoceles triangle] -- :math:`∠DBK = θ` -- :math:`BD = u1` - -We can deduce the following facts using geometry. - -- :math:`t - u - v = φ` -- :math:`D(x - sin(φ), y + cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BD>)` -- :math:`BC = CD = 2` [2 * radius of curvature] -- :math:`cos(2π - u) = \frac{BC^2 + CD^2 - BD^2}{2 * BC * CD}` [Cosine Rule] -- :math:`\frac{sin(A)}{BC} = \frac{sin(u)}{u1}` [Sine Rule] -- :math:`∠ABK = \frac{π}{2}` -- :math:`∠KBD = θ` -- :math:`t = ∠ABK + ∠KBD - ∠DBC` - -Hence, we have: - -- :math:`u1, θ = polar(x - sin(φ), y + cos(φ) - 1)` -- :math:`u = arccos(1 - \frac{u1^2}{8})` -- :math:`A = arcsin(\frac{sin(u)}{u1}*2)` -- :math:`t = \frac{π}{2} + θ - A` -- :math:`v = (t - u - φ)` - -6. **Left-RightxLeft-Right** - -.. image:: LR_LR.png - -With followng notations: - -- :math:`∠CLG = ∠BCL = ∠CBG = ∠LGB = A = u` [BGCL is an isoceles trapezium] -- :math:`∠KBG = θ` -- :math:`BG = u1` - -We can deduce the following facts using geometry. - -- :math:`t - 2u + v = φ` -- :math:`G(x + sin(φ), y - cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BG>)` -- :math:`BC = CL = LG = 2` [2 * radius of curvature] -- :math:`CG^2 = CL^2 + LG^2 - 2*CL*LG*cos(A)` [Cosine rule in LGC] -- :math:`CG^2 = CL^2 + LG^2 - 2*CL*LG*cos(A)` [Cosine rule in LGC] -- From the previous two equations: :math:`A = arccos(\frac{u1 + 2}{4})` -- :math:`∠ABK = \frac{π}{2}` -- :math:`t = ∠ABK + ∠KBG + ∠GBC` - -Hence, we have: - -- :math:`u1, θ = polar(x + sin(φ), y - cos(φ) - 1)` -- :math:`u = arccos(\frac{u1 + 2}{4})` -- :math:`t = \frac{π}{2} + θ + u` -- :math:`v = (φ - t + 2u)` - -7. **LeftxRight-LeftxRight** - -.. image:: L_RL_R.png - -With followng notations: - -- :math:`∠GBC = A` [BGCL is an isoceles trapezium] -- :math:`∠KBG = θ` -- :math:`BG = u1` - -We can deduce the following facts using geometry. - -- :math:`t - v = φ` -- :math:`G(x + sin(φ), y - cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BG>)` -- :math:`BC = CL = LG = 2` [2 * radius of curvature] -- :math:`CD = 1` [radius of curvature] -- D is midpoint of BG -- :math:`BD = \frac{u1}{2}` -- :math:`cos(u) = \frac{BC^2 + CD^2 - BD^2}{2*BC*CD}` [Cosine rule in BCD] -- :math:`sin(A) = CD*\frac{sin(u)}{BD}` [Sine rule in BCD] -- :math:`∠ABK = \frac{π}{2}` -- :math:`t = ∠ABK + ∠KBG + ∠GBC` - -Hence, we have: - -- :math:`u1, θ = polar(x + sin(φ), y - cos(φ) - 1)` -- :math:`u = arccos(\frac{20 - u1^2}{16})` -- :math:`A = arcsin(2*\frac{sin(u)}{u1})` -- :math:`t = \frac{π}{2} + θ + A` -- :math:`v = (t - φ)` - - -8. **LeftxRight90-Straight-Left** - -.. image:: L_R90SL.png - -With followng notations: - -- :math:`∠FBM = A` [BGCL is an isoceles trapezium] -- :math:`∠KBF = θ` -- :math:`BF = u1` - -We can deduce the following facts using geometry. - -- :math:`t + \frac{π}{2} - v = φ` -- :math:`F(x - sin(φ), y + cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BF>)` -- :math:`BM = CB = 2` [2 * radius of curvature] -- :math:`MD = CD = 1` [CGDM is a rectangle] -- :math:`MC = GD = u` [CGDM is a rectangle] -- :math:`MF = MD + DF = 2` -- :math:`BM = \sqrt{BF^2 - MF^2}` [Pythagoras theorem on BFM] -- :math:`tan(A) = \frac{MF}{BM}` -- :math:`u = MC = BM - CB` -- :math:`t = ∠ABK + ∠KBF + ∠FBC` - -Hence, we have: - -- :math:`u1, θ = polar(x - sin(φ), y + cos(φ) - 1)` -- :math:`u = arccos(\sqrt{u1^2 - 4} - 2)` -- :math:`A = arctan(\frac{2}{\sqrt{u1^2 - 4}})` -- :math:`t = \frac{π}{2} + θ + A` -- :math:`v = (t - φ + \frac{π}{2})` - - -9. **Left-Straight-Right90xLeft** - -.. image:: LSR90_L.png - -With followng notations: - -- :math:`∠MBH = A` [BGCL is an isoceles trapezium] -- :math:`∠KBH = θ` -- :math:`BH = u1` - -We can deduce the following facts using geometry. - -- :math:`t - \frac{π}{2} - v = φ` -- :math:`H(x - sin(φ), y + cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BH>)` -- :math:`GH = 2` [2 * radius of curvature] -- :math:`CM = DG = 1` [CGDM is a rectangle] -- :math:`CD = MG = u` [CGDM is a rectangle] -- :math:`BM = BC + CM = 2` -- :math:`MH = \sqrt{BH^2 - BM^2}` [Pythagoras theorem on BHM] -- :math:`tan(A) = \frac{HM}{BM}` -- :math:`u = MC = BM - CB` -- :math:`t = ∠ABK + ∠KBH - ∠HBC` - -Hence, we have: - -- :math:`u1, θ = polar(x - sin(φ), y + cos(φ) - 1)` -- :math:`u = arccos(\sqrt{u1^2 - 4} - 2)` -- :math:`A = arctan(\frac{2}{\sqrt{u1^2 - 4}})` -- :math:`t = \frac{π}{2} + θ - A` -- :math:`v = (t - φ - \frac{π}{2})` - - -10. **LeftxRight90-Straight-Right** - -.. image:: L_R90SR.png - -With followng notations: - -- :math:`∠KBG = θ` -- :math:`BG = u1` - -We can deduce the following facts using geometry. - -- :math:`t - \frac{π}{2} - v = φ` -- :math:`G(x + sin(φ), y - cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BG>)` -- :math:`BD = 2` [2 * radius of curvature] -- :math:`DG = EF = u` [DGFE is a rectangle] -- :math:`DG = BG - BD = 2` -- :math:`∠ABK = \frac{π}{2}` -- :math:`t = ∠ABK + ∠KBG` - -Hence, we have: - -- :math:`u1, θ = polar(x + sin(φ), y - cos(φ) - 1)` -- :math:`u = u1 - 2` -- :math:`t = \frac{π}{2} + θ` -- :math:`v = (t - φ - \frac{π}{2})` - - -11. **Left-Straight-Left90xRight** - -.. image:: LSL90xR.png - -With followng notations: - -- :math:`∠KBH = θ` -- :math:`BH = u1` - -We can deduce the following facts using geometry. - -- :math:`t + \frac{π}{2} + v = φ` -- :math:`H(x + sin(φ), y - cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BH>)` -- :math:`GH = 2` [2 * radius of curvature] -- :math:`DC = BG = u` [DGBC is a rectangle] -- :math:`BG = BH - GH` -- :math:`∠ABC= ∠KBH` - -Hence, we have: - -- :math:`u1, θ = polar(x + sin(φ), y - cos(φ) - 1)` -- :math:`u = u1 - 2` -- :math:`t = θ` -- :math:`v = (φ - t - \frac{π}{2})` - - -12. **LeftxRight90-Straight-Left90xRight** - -.. image:: L_R90SL90_R.png - -With followng notations: - -- :math:`∠KBH = θ` -- :math:`∠HBM = A` -- :math:`BH = u1` - -We can deduce the following facts using geometry. - -- :math:`t - v = φ` -- :math:`H(x + sin(φ), y - cos(φ))` -- :math:`B(0, 1)` -- :math:`u1, θ = polar(vector<BH>)` -- :math:`GF = ED = 1` [radius of curvature] -- :math:`BD = GH = 2` [2 * radius of curvature] -- :math:`FN = GH = 2` [ENMD is a rectangle] -- :math:`NH = GF = 1` [FNHG is a rectangle] -- :math:`MN = ED = 1` [ENMD is a rectangle] -- :math:`DO = EF = u` [DOFE is a rectangle] -- :math:`MH = MN + NH = 2` -- :math:`BM = \sqrt{BH^2 - MH^2}` [Pythagoras theorem on BHM] -- :math:`DO = BM - BD - OM` -- :math:`tan(A) = \frac{MH}{BM}` -- :math:`∠ABC = ∠ABK + ∠KBH + ∠HBM` - -Hence, we have: - -- :math:`u1, θ = polar(x + sin(φ), y - cos(φ) - 1)` -- :math:`u = /sqrt{u1^2 - 4} - 4` -- :math:`A = arctan(\frac{2}{u1^2 - 4})` -- :math:`t = \frac{π}{2} + θ + A` -- :math:`v = (t - φ)` - - -Ref: - -- `15.3.2 Reeds-Shepp - Curves <https://lavalle.pl/planning/node822.html>`__ - -- `optimal paths for a car that goes both forwards and - backwards <https://pdfs.semanticscholar.org/932e/c495b1d0018fd59dee12a0bf74434fac7af4.pdf>`__ - -- `ghliu/pyReedsShepp: Implementation of Reeds Shepp - curve. <https://github.com/ghliu/pyReedsShepp>`__ diff --git a/docs/modules/5_path_planning/rrt/figure_1.png b/docs/modules/5_path_planning/rrt/figure_1.png deleted file mode 100644 index 959a28b482c..00000000000 Binary files a/docs/modules/5_path_planning/rrt/figure_1.png and /dev/null differ diff --git a/docs/modules/5_path_planning/rrt/rrt_star.rst b/docs/modules/5_path_planning/rrt/rrt_star.rst deleted file mode 100644 index 6deb6b91726..00000000000 --- a/docs/modules/5_path_planning/rrt/rrt_star.rst +++ /dev/null @@ -1,21 +0,0 @@ -RRT\* -~~~~~ - -.. figure:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTstar/animation.gif - -This is a path planning code with RRT\* - -Black circles are obstacles, green line is a searched tree, red crosses are start and goal positions. - -Simulation -^^^^^^^^^^ - -.. image:: rrt_star/rrt_star_1_0.png - :width: 600px - - -Ref -^^^ -- `Sampling-based Algorithms for Optimal Motion Planning <https://arxiv.org/pdf/1105.1186>`__ -- `Incremental Sampling-based Algorithms for Optimal Motion Planning <https://arxiv.org/abs/1005.0416>`__ - diff --git a/docs/modules/5_path_planning/rrt/rrt_star_reeds_shepp/figure_1.png b/docs/modules/5_path_planning/rrt/rrt_star_reeds_shepp/figure_1.png deleted file mode 100644 index 2dcbe258c5c..00000000000 Binary files a/docs/modules/5_path_planning/rrt/rrt_star_reeds_shepp/figure_1.png and /dev/null differ diff --git a/docs/modules/5_path_planning/state_lattice_planner/Figure_1.png b/docs/modules/5_path_planning/state_lattice_planner/Figure_1.png deleted file mode 100644 index 259b2dfa41b..00000000000 Binary files a/docs/modules/5_path_planning/state_lattice_planner/Figure_1.png and /dev/null differ diff --git a/docs/modules/5_path_planning/state_lattice_planner/Figure_2.png b/docs/modules/5_path_planning/state_lattice_planner/Figure_2.png deleted file mode 100644 index 6e9b4758cd4..00000000000 Binary files a/docs/modules/5_path_planning/state_lattice_planner/Figure_2.png and /dev/null differ diff --git a/docs/modules/5_path_planning/state_lattice_planner/Figure_3.png b/docs/modules/5_path_planning/state_lattice_planner/Figure_3.png deleted file mode 100644 index 09a4909dd10..00000000000 Binary files a/docs/modules/5_path_planning/state_lattice_planner/Figure_3.png and /dev/null differ diff --git a/docs/modules/5_path_planning/state_lattice_planner/Figure_4.png b/docs/modules/5_path_planning/state_lattice_planner/Figure_4.png deleted file mode 100644 index 3c468efd572..00000000000 Binary files a/docs/modules/5_path_planning/state_lattice_planner/Figure_4.png and /dev/null differ diff --git a/docs/modules/5_path_planning/state_lattice_planner/Figure_5.png b/docs/modules/5_path_planning/state_lattice_planner/Figure_5.png deleted file mode 100644 index 0f45d93081a..00000000000 Binary files a/docs/modules/5_path_planning/state_lattice_planner/Figure_5.png and /dev/null differ diff --git a/docs/modules/5_path_planning/state_lattice_planner/Figure_6.png b/docs/modules/5_path_planning/state_lattice_planner/Figure_6.png deleted file mode 100644 index d1a3c9945dc..00000000000 Binary files a/docs/modules/5_path_planning/state_lattice_planner/Figure_6.png and /dev/null differ diff --git a/docs/modules/5_path_planning/time_based_grid_search/time_based_grid_search_main.rst b/docs/modules/5_path_planning/time_based_grid_search/time_based_grid_search_main.rst deleted file mode 100644 index 04001d45044..00000000000 --- a/docs/modules/5_path_planning/time_based_grid_search/time_based_grid_search_main.rst +++ /dev/null @@ -1,80 +0,0 @@ -Time based grid search ----------------------- - -Space-time astar -~~~~~~~~~~~~~~~~~~~~~~ - -This is an extension of A* algorithm that supports planning around dynamic obstacles. - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/TimeBasedPathPlanning/SpaceTimeAStar/path_animation.gif - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/TimeBasedPathPlanning/SpaceTimeAStar/path_animation2.gif - -The key difference of this algorithm compared to vanilla A* is that the cost and heuristic are now time-based instead of distance-based. -Using a time-based cost and heuristic ensures the path found is optimal in terms of time to reach the goal. - -The cost is the amount of time it takes to reach a given node, and the heuristic is the minimum amount of time it could take to reach the goal from that node, disregarding all obstacles. -For a simple scenario where the robot can move 1 cell per time step and stop and go as it pleases, the heuristic for time is equivalent to the heuristic for distance. - -One optimization that was added in `this PR <https://github.com/AtsushiSakai/PythonRobotics/pull/1183>`__ was to add an expanded set to the algorithm. The algorithm will not expand nodes that are already in that set. This greatly reduces the number of node expansions needed to find a path, since no duplicates are expanded. It also helps to reduce the amount of memory the algorithm uses. - -Before:: - - Found path to goal after 204490 expansions - Planning took: 1.72464 seconds - Memory usage (RSS): 68.19 MB - - -After:: - - Found path to goal after 2348 expansions - Planning took: 0.01550 seconds - Memory usage (RSS): 64.85 MB - -When starting at (1, 11) in the structured obstacle arrangement (second of the two gifs above). - - -Safe Interval Path Planning -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The safe interval path planning algorithm is described in this paper: - -`SIPP: Safe Interval Path Planning for Dynamic Environments <https://www.cs.cmu.edu/~maxim/files/sipp_icra11.pdf>`__ - -It is faster than space-time A* because it pre-computes the intervals of time that are unoccupied in each cell. This allows it to reduce the number of successor node it generates by avoiding nodes within the same interval. - -**Comparison with SpaceTime A*:** - -Arrangement 1 starting at (1, 18) - -SafeInterval planner:: - - Found path to goal after 322 expansions - Planning took: 0.00730 seconds - -SpaceTime A*:: - - Found path to goal after 2717154 expansions - Planning took: 20.51330 seconds - -**Benchmarking the Safe Interval Path Planner:** - -250 random obstacles:: - - Found path to goal after 764 expansions - Planning took: 0.60596 seconds - -.. image:: https://raw.githubusercontent.com/AtsushiSakai/PythonRoboticsGifs/refs/heads/master/PathPlanning/TimeBasedPathPlanning/SafeIntervalPathPlanner/path_animation.gif - -Arrangement 1 starting at (1, 18):: - - Found path to goal after 322 expansions - Planning took: 0.00730 seconds - -.. image:: https://raw.githubusercontent.com/AtsushiSakai/PythonRoboticsGifs/refs/heads/master/PathPlanning/TimeBasedPathPlanning/SafeIntervalPathPlanner/path_animation2.gif - -References -~~~~~~~~~~~ - -- `Cooperative Pathfinding <https://www.davidsilver.uk/wp-content/uploads/2020/03/coop-path-AIWisdom.pdf>`__ -- `SIPP: Safe Interval Path Planning for Dynamic Environments <https://www.cs.cmu.edu/~maxim/files/sipp_icra11.pdf>`__ diff --git a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst b/docs/modules/6_path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst deleted file mode 100644 index ded187e972d..00000000000 --- a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst +++ /dev/null @@ -1,140 +0,0 @@ -.. _linearquadratic-regulator-(lqr)-speed-and-steering-control: - -Linear–quadratic regulator (LQR) speed and steering control ------------------------------------------------------------ - -Path tracking simulation with LQR speed and steering control. - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_speed_steer_control/animation.gif - -`[Code Link] <https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathTracking/lqr_speed_steer_control/lqr_speed_steer_control.py>`_ - -Overview -~~~~~~~~ - -The LQR (Linear Quadratic Regulator) speed and steering control model implemented in `lqr_speed_steer_control.py` provides a simulation -for an autonomous vehicle to track: - -1. A desired speed by adjusting acceleration based on feedback from the current state and the desired speed. - -2. A desired trajectory by adjusting steering angle based on feedback from the current state and the desired trajectory. - -by only using one LQT controller. - -Vehicle motion Model -~~~~~~~~~~~~~~~~~~~~~ - -The below figure shows the geometric model of the vehicle used in this simulation: - -.. image:: lqr_steering_control_model.jpg - :width: 600px - -The `e`, :math:`{\theta}`, and :math:`\upsilon` represent the lateral error, orientation error, and velocity error, respectively, with respect to the desired trajectory and speed. -And :math:`\dot{e}` and :math:`\dot{\theta}` represent the rates of change of these errors. - -The :math:`e_t` and :math:`\theta_t`, and :math:`\upsilon` are the updated values of `e`, :math:`\theta`, :math:`\upsilon` and at time `t`, respectively, and can be calculated using the following kinematic equations: - -.. math:: e_t = e_{t-1} + \dot{e}_{t-1} dt - -.. math:: \theta_t = \theta_{t-1} + \dot{\theta}_{t-1} dt - -.. math:: \upsilon_t = \upsilon_{t-1} + a_{t-1} dt - -Where `dt` is the time difference and :math:`a_t` is the acceleration at the time `t`. - -The change rate of the `e` can be calculated as: - -.. math:: \dot{e}_t = V \sin(\theta_{t-1}) - -Where `V` is the current vehicle speed. - -If the :math:`\theta` is small, - -.. math:: \theta \approx 0 - -the :math:`\sin(\theta)` can be approximated as :math:`\theta`: - -.. math:: \sin(\theta) = \theta - -So, the change rate of the `e` can be approximated as: - -.. math:: \dot{e}_t = V \theta_{t-1} - -The change rate of the :math:`\theta` can be calculated as: - -.. math:: \dot{\theta}_t = \frac{V}{L} \tan(\delta) - -where `L` is the wheelbase of the vehicle and :math:`\delta` is the steering angle. - -If the :math:`\delta` is small, - -.. math:: \delta \approx 0 - -the :math:`\tan(\delta)` can be approximated as :math:`\delta`: - -.. math:: \tan(\delta) = \delta - -So, the change rate of the :math:`\theta` can be approximated as: - -.. math:: \dot{\theta}_t = \frac{V}{L} \delta - -The above equations can be used to update the state of the vehicle at each time step. - -Control Model -~~~~~~~~~~~~~~ - -To formulate the state-space representation of the vehicle dynamics as a linear model, -the state vector `x` and control input vector `u` are defined as follows: - -.. math:: x_t = [e_t, \dot{e}_t, \theta_t, \dot{\theta}_t, \upsilon_t]^T - -.. math:: u_t = [\delta_t, a_t]^T - -The linear state transition equation can be represented as: - -.. math:: x_{t+1} = A x_t + B u_t - -where: - -:math:`\begin{equation*} A = \begin{bmatrix} 1 & dt & 0 & 0 & 0\\ 0 & 0 & v & 0 & 0\\ 0 & 0 & 1 & dt & 0\\ 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 & 1\\\end{bmatrix} \end{equation*}` - -:math:`\begin{equation*} B = \begin{bmatrix} 0 & 0\\ 0 & 0\\ 0 & 0\\ \frac{v}{L} & 0\\ 0 & dt \\ \end{bmatrix} \end{equation*}` - -LQR controller -~~~~~~~~~~~~~~~ - -The Linear Quadratic Regulator (LQR) controller is used to calculate the optimal control input `u` that minimizes the quadratic cost function: - -:math:`J = \sum_{t=0}^{N} (x_t^T Q x_t + u_t^T R u_t)` - -where `Q` and `R` are the weighting matrices for the state and control input, respectively. - -for the linear model: - -:math:`x_{t+1} = A x_t + B u_t` - -The optimal control input `u` can be calculated as: - -:math:`u_t = -K x_t` - -where `K` is the feedback gain matrix obtained by solving the Riccati equation. - -Simulation results -~~~~~~~~~~~~~~~~~~~ - - -.. image:: x-y.png - :width: 600px - -.. image:: yaw.png - :width: 600px - -.. image:: speed.png - :width: 600px - - - -References: -~~~~~~~~~~~ - -- `Towards fully autonomous driving: Systems and algorithms <https://ieeexplore.ieee.org/document/5940562/>`__ diff --git a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/lqr_steering_control_model.jpg b/docs/modules/6_path_tracking/lqr_speed_and_steering_control/lqr_steering_control_model.jpg deleted file mode 100644 index 83754d5bb01..00000000000 Binary files a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/lqr_steering_control_model.jpg and /dev/null differ diff --git a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/speed.png b/docs/modules/6_path_tracking/lqr_speed_and_steering_control/speed.png deleted file mode 100644 index ae99eb7ea3d..00000000000 Binary files a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/speed.png and /dev/null differ diff --git a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/x-y.png b/docs/modules/6_path_tracking/lqr_speed_and_steering_control/x-y.png deleted file mode 100644 index bff3f1a786e..00000000000 Binary files a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/x-y.png and /dev/null differ diff --git a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/yaw.png b/docs/modules/6_path_tracking/lqr_speed_and_steering_control/yaw.png deleted file mode 100644 index 7f3d9c1d10b..00000000000 Binary files a/docs/modules/6_path_tracking/lqr_speed_and_steering_control/yaw.png and /dev/null differ diff --git a/docs/modules/6_path_tracking/lqr_steering_control/lqr_steering_control_main.rst b/docs/modules/6_path_tracking/lqr_steering_control/lqr_steering_control_main.rst deleted file mode 100644 index baca7a33fc4..00000000000 --- a/docs/modules/6_path_tracking/lqr_steering_control/lqr_steering_control_main.rst +++ /dev/null @@ -1,121 +0,0 @@ -.. _linearquadratic-regulator-(lqr)-steering-control: - -Linear–quadratic regulator (LQR) steering control -------------------------------------------------- - -Path tracking simulation with LQR steering control and PID speed -control. - -.. image:: https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_steer_control/animation.gif - -`[Code Link] <https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathTracking/lqr_steer_control/lqr_steer_control.py>`_ - -Overview -~~~~~~~~ - -The LQR (Linear Quadratic Regulator) steering control model implemented in lqr_steer_control.py provides a simulation -for an autonomous vehicle to track a desired trajectory by adjusting steering angle based on feedback from the current state and the desired trajectory. -This model utilizes a combination of PID speed control and LQR steering control to achieve smooth and accurate trajectory tracking. - -Vehicle motion Model -~~~~~~~~~~~~~~~~~~~~~ - -The below figure shows the geometric model of the vehicle used in this simulation: - -.. image:: lqr_steering_control_model.jpg - :width: 600px - -The `e` and :math:`\theta` represent the lateral error and orientation error, respectively, with respect to the desired trajectory. -And :math:`\dot{e}` and :math:`\dot{\theta}` represent the rates of change of these errors. - -The :math:`e_t` and :math:`\theta_t` are the updated values of `e` and :math:`\theta` at time `t`, respectively, and can be calculated using the following kinematic equations: - -.. math:: e_t = e_{t-1} + \dot{e}_{t-1} dt - -.. math:: \theta_t = \theta_{t-1} + \dot{\theta}_{t-1} dt - -Where `dt` is the time difference. - -The change rate of the `e` can be calculated as: - -.. math:: \dot{e}_t = V \sin(\theta_{t-1}) - -Where `V` is the current vehicle speed. - -If the :math:`\theta` is small, - -.. math:: \theta \approx 0 - -the :math:`\sin(\theta)` can be approximated as :math:`\theta`: - -.. math:: \sin(\theta) = \theta - -So, the change rate of the `e` can be approximated as: - -.. math:: \dot{e}_t = V \theta_{t-1} - -The change rate of the :math:`\theta` can be calculated as: - -.. math:: \dot{\theta}_t = \frac{V}{L} \tan(\delta) - -where `L` is the wheelbase of the vehicle and :math:`\delta` is the steering angle. - -If the :math:`\delta` is small, - -.. math:: \delta \approx 0 - -the :math:`\tan(\delta)` can be approximated as :math:`\delta`: - -.. math:: \tan(\delta) = \delta - -So, the change rate of the :math:`\theta` can be approximated as: - -.. math:: \dot{\theta}_t = \frac{V}{L} \delta - -The above equations can be used to update the state of the vehicle at each time step. - -Control Model -~~~~~~~~~~~~~~ - -To formulate the state-space representation of the vehicle dynamics as a linear model, -the state vector `x` and control input vector `u` are defined as follows: - -.. math:: x_t = [e_t, \dot{e}_t, \theta_t, \dot{\theta}_t]^T - -.. math:: u_t = \delta_t - -The linear state transition equation can be represented as: - -.. math:: x_{t+1} = A x_t + B u_t - -where: - -:math:`\begin{equation*} A = \begin{bmatrix} 1 & dt & 0 & 0\\ 0 & 0 & v & 0\\ 0 & 0 & 1 & dt\\ 0 & 0 & 0 & 0 \\ \end{bmatrix} \end{equation*}` - -:math:`\begin{equation*} B = \begin{bmatrix} 0\\ 0\\ 0\\ \frac{v}{L} \\ \end{bmatrix} \end{equation*}` - -LQR controller -~~~~~~~~~~~~~~~ - -The Linear Quadratic Regulator (LQR) controller is used to calculate the optimal control input `u` that minimizes the quadratic cost function: - -:math:`J = \sum_{t=0}^{N} (x_t^T Q x_t + u_t^T R u_t)` - -where `Q` and `R` are the weighting matrices for the state and control input, respectively. - -for the linear model: - -:math:`x_{t+1} = A x_t + B u_t` - -The optimal control input `u` can be calculated as: - -:math:`u_t = -K x_t` - -where `K` is the feedback gain matrix obtained by solving the Riccati equation. - -References: -~~~~~~~~~~~ -- `ApolloAuto/apollo: An open autonomous driving platform <https://github.com/ApolloAuto/apollo>`_ - -- `Linear Quadratic Regulator (LQR) <https://en.wikipedia.org/wiki/Linear%E2%80%93quadratic_regulator>`_ - diff --git a/docs/modules/6_path_tracking/lqr_steering_control/lqr_steering_control_model.jpg b/docs/modules/6_path_tracking/lqr_steering_control/lqr_steering_control_model.jpg deleted file mode 100644 index 83754d5bb01..00000000000 Binary files a/docs/modules/6_path_tracking/lqr_steering_control/lqr_steering_control_model.jpg and /dev/null differ diff --git a/docs/modules/6_path_tracking/path_tracking_main.rst b/docs/modules/6_path_tracking/path_tracking_main.rst deleted file mode 100644 index d98e3245835..00000000000 --- a/docs/modules/6_path_tracking/path_tracking_main.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _`Path Tracking`: - -Path Tracking -============= - -Path tracking is the ability of a robot to follow the reference path generated by a path planner while simultaneously stabilizing the robot. The path tracking controller may need to account for modeling error and other forms of uncertainty. In path tracking, feedback control techniques and optimization based control techniques are widely used[22]. Fig.6 shows simulations using rear wheel feedback steering control and PID speed control, and iterative linear model predictive path tracking control[27]. - -.. toctree:: - :maxdepth: 2 - :caption: Contents - - pure_pursuit_tracking/pure_pursuit_tracking - stanley_control/stanley_control - rear_wheel_feedback_control/rear_wheel_feedback_control - lqr_steering_control/lqr_steering_control - lqr_speed_and_steering_control/lqr_speed_and_steering_control - model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control - cgmres_nmpc/cgmres_nmpc - move_to_a_pose_control/move_to_a_pose_control diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000000..93263535e61 --- /dev/null +++ b/genindex.html @@ -0,0 +1,323 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Index — PythonRobotics documentation</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/clipboard.min.js"></script> + <script src="_static/copybutton.js"></script> + <script src="_static/dark_mode_js/default_dark.js"></script> + <script src="_static/dark_mode_js/theme_switcher.js"></script> + <script src="_static/js/theme.js"></script> + <link rel="index" title="Index" href="#" /> + <link rel="search" title="Search" href="search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="index.html" class="icon icon-home"> PythonRobotics + <img src="_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="index.html" class="icon icon-home"></a> »</li> + <li>Index</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/genindex" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + +<h1 id="index">Index</h1> + +<div class="genindex-jumpbox"> + <a href="#A"><strong>A</strong></a> + | <a href="#C"><strong>C</strong></a> + | <a href="#D"><strong>D</strong></a> + | <a href="#E"><strong>E</strong></a> + | <a href="#F"><strong>F</strong></a> + | <a href="#G"><strong>G</strong></a> + | <a href="#I"><strong>I</strong></a> + | <a href="#L"><strong>L</strong></a> + | <a href="#M"><strong>M</strong></a> + | <a href="#N"><strong>N</strong></a> + | <a href="#P"><strong>P</strong></a> + | <a href="#R"><strong>R</strong></a> + | <a href="#V"><strong>V</strong></a> + +</div> +<h2 id="A">A</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/path_planning/bspline_path/bspline_path.html#PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path">approximate_b_spline_path() (in module PathPlanning.BSplinePath.bspline_path)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="C">C</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_curvature">calc_curvature() (PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D method)</a> +</li> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_first_derivative">calc_first_derivative() (PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D method)</a> +</li> + <li><a href="modules/mapping/normal_vector_estimation/normal_vector_estimation.html#Mapping.normal_vector_estimation.normal_vector_estimation.calc_normal_vector">calc_normal_vector() (in module Mapping.normal_vector_estimation.normal_vector_estimation)</a> +</li> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_position">calc_position() (PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D method)</a> + + <ul> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_position">(PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D method)</a> +</li> + </ul></li> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_second_derivative">calc_second_derivative() (PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D method)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_yaw">calc_yaw() (PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D method)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.center_grid_x">center_grid_x (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.center_grid_y">center_grid_y (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.covariance">covariance (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.criteria">criteria (Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting attribute)</a> +</li> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D">CubicSpline1D (class in PathPlanning.CubicSpline.cubic_spline_planner)</a> +</li> + <li><a href="modules/path_planning/cubic_spline/cubic_spline.html#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D">CubicSpline2D (class in PathPlanning.CubicSpline.cubic_spline_planner)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="D">D</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.d_theta_deg_for_search">d_theta_deg_for_search (Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting attribute)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="E">E</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.eig_values">eig_values (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.eig_vec">eig_vec (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="F">F</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/point_cloud_sampling/point_cloud_sampling.html#Mapping.point_cloud_sampling.point_cloud_sampling.farthest_point_sampling">farthest_point_sampling() (in module Mapping.point_cloud_sampling.point_cloud_sampling)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.fitting">fitting() (Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting method)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="G">G</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.grid_index_map">grid_index_map (Mapping.ndt_map.ndt_map.NDTMap attribute)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="I">I</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/path_planning/bspline_path/bspline_path.html#PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path">interpolate_b_spline_path() (in module PathPlanning.BSplinePath.bspline_path)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="L">L</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting">LShapeFitting (class in Mapping.rectangle_fitting.rectangle_fitting)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Criteria">LShapeFitting.Criteria (class in Mapping.rectangle_fitting.rectangle_fitting)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="M">M</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.mean_x">mean_x (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.mean_y">mean_y (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.min_dist_of_closeness_criteria">min_dist_of_closeness_criteria (Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting attribute)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.min_n_points">min_n_points (Mapping.ndt_map.ndt_map.NDTMap attribute)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="N">N</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.n_points">n_points (Mapping.ndt_map.ndt_map.NDTMap.NDTGrid attribute)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap">NDTMap (class in Mapping.ndt_map.ndt_map)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid">NDTMap.NDTGrid (class in Mapping.ndt_map.ndt_map)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="P">P</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/path_planning/dubins_path/dubins_path.html#PathPlanning.DubinsPath.dubins_path_planner.plan_dubins_path">plan_dubins_path() (in module PathPlanning.DubinsPath.dubins_path_planner)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/utils/plot/plot.html#utils.plot.plot_curvature">plot_curvature() (in module utils.plot)</a> +</li> + <li><a href="modules/mapping/point_cloud_sampling/point_cloud_sampling.html#Mapping.point_cloud_sampling.point_cloud_sampling.poisson_disk_sampling">poisson_disk_sampling() (in module Mapping.point_cloud_sampling.point_cloud_sampling)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="R">R</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.R0">R0 (Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting attribute)</a> +</li> + <li><a href="modules/mapping/normal_vector_estimation/normal_vector_estimation.html#Mapping.normal_vector_estimation.normal_vector_estimation.ransac_normal_vector_estimation">ransac_normal_vector_estimation() (in module Mapping.normal_vector_estimation.normal_vector_estimation)</a> +</li> + </ul></td> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/rectangle_fitting/rectangle_fitting.html#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Rd">Rd (Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting attribute)</a> +</li> + <li><a href="modules/mapping/ndt_map/ndt_map.html#Mapping.ndt_map.ndt_map.NDTMap.resolution">resolution (Mapping.ndt_map.ndt_map.NDTMap attribute)</a> +</li> + </ul></td> +</tr></table> + +<h2 id="V">V</h2> +<table style="width: 100%" class="indextable genindextable"><tr> + <td style="width: 33%; vertical-align: top;"><ul> + <li><a href="modules/mapping/point_cloud_sampling/point_cloud_sampling.html#Mapping.point_cloud_sampling.point_cloud_sampling.voxel_point_sampling">voxel_point_sampling() (in module Mapping.point_cloud_sampling.point_cloud_sampling)</a> +</li> + </ul></td> +</tr></table> + + + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/getting_started.html b/getting_started.html new file mode 100644 index 00000000000..3a84fcce965 --- /dev/null +++ b/getting_started.html @@ -0,0 +1,202 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Getting Started — PythonRobotics documentation</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/clipboard.min.js"></script> + <script src="_static/copybutton.js"></script> + <script src="_static/dark_mode_js/default_dark.js"></script> + <script src="_static/dark_mode_js/theme_switcher.js"></script> + <script src="_static/js/theme.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + <link rel="next" title="Introduction" href="modules/introduction.html" /> + <link rel="prev" title="Welcome to PythonRobotics’s documentation!" href="index.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="index.html" class="icon icon-home"> PythonRobotics + <img src="_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Getting Started</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#what-is-this">What is this?</a></li> +<li class="toctree-l2"><a class="reference internal" href="#requirements">Requirements</a></li> +<li class="toctree-l2"><a class="reference internal" href="#how-to-use">How to use</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="index.html" class="icon icon-home"></a> »</li> + <li>Getting Started</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/getting_started_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="getting-started"> +<span id="id1"></span><h1>Getting Started<a class="headerlink" href="#getting-started" title="Permalink to this headline"></a></h1> +<section id="what-is-this"> +<h2>What is this?<a class="headerlink" href="#what-is-this" title="Permalink to this headline"></a></h2> +<p>This is an Open Source Software (OSS) project: PythonRobotics, which is a Python code collection of robotics algorithms.</p> +<p>The focus of the project is on autonomous navigation, and the goal is for beginners in robotics to understand the basic ideas behind each algorithm.</p> +<p>In this project, the algorithms which are practical and widely used in both academia and industry are selected.</p> +<p>Each sample code is written in Python3 and only depends on some standard modules for readability and ease of use.</p> +<p>It includes intuitive animations to understand the behavior of the simulation.</p> +<p>See this paper for more details:</p> +<ul class="simple"> +<li><p>PythonRobotics: a Python code collection of robotics algorithms: <a class="reference external" href="https://arxiv.org/abs/1808.10703">https://arxiv.org/abs/1808.10703</a></p></li> +</ul> +</section> +<section id="requirements"> +<span id="id2"></span><h2>Requirements<a class="headerlink" href="#requirements" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.python.org/">Python 3.11.x</a></p></li> +<li><p><a class="reference external" href="https://numpy.org/">NumPy</a></p></li> +<li><p><a class="reference external" href="https://scipy.org/">SciPy</a></p></li> +<li><p><a class="reference external" href="https://matplotlib.org/">Matplotlib</a></p></li> +<li><p><a class="reference external" href="https://www.cvxpy.org/">cvxpy</a></p></li> +</ul> +<p>For development:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://docs.pytest.org/en/latest/">pytest</a> (for unit tests)</p></li> +<li><p><a class="reference external" href="https://github.com/pytest-dev/pytest-xdist">pytest-xdist</a> (for parallel unit tests)</p></li> +<li><p><a class="reference external" href="https://mypy-lang.org/">mypy</a> (for type check)</p></li> +<li><p><a class="reference external" href="https://www.sphinx-doc.org/en/master/index.html">sphinx</a> (for document generation)</p></li> +<li><p><a class="reference external" href="https://github.com/charliermarsh/ruff">ruff</a> (for code style check)</p></li> +</ul> +</section> +<section id="how-to-use"> +<h2>How to use<a class="headerlink" href="#how-to-use" title="Permalink to this headline"></a></h2> +<ol class="arabic simple"> +<li><p>Clone this repo and go into dir.</p></li> +</ol> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>$ git clone https://github.com/AtsushiSakai/PythonRobotics.git + +>$ cd PythonRobotics +</pre></div> +</div> +<ol class="arabic simple" start="2"> +<li><p>Install the required libraries.</p></li> +</ol> +<p>using conda :</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>$ conda env create -f requirements/environment.yml +</pre></div> +</div> +<p>using pip :</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>$ pip install -r requirements/requirements.txt +</pre></div> +</div> +<ol class="arabic simple" start="3"> +<li><p>Execute python script in each directory.</p></li> +<li><p>Add star to this repo if you like it 😃.</p></li> +</ol> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="index.html" class="btn btn-neutral float-left" title="Welcome to PythonRobotics’s documentation!" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="modules/introduction.html" class="btn btn-neutral float-right" title="Introduction" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/how_to_contribute.html b/how_to_contribute.html new file mode 100644 index 00000000000..6d75579903a --- /dev/null +++ b/how_to_contribute.html @@ -0,0 +1,252 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>How To Contribute — PythonRobotics documentation</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/clipboard.min.js"></script> + <script src="_static/copybutton.js"></script> + <script src="_static/dark_mode_js/default_dark.js"></script> + <script src="_static/dark_mode_js/theme_switcher.js"></script> + <script src="_static/js/theme.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + <link rel="prev" title="KF Basics - Part 2" href="modules/appendix/Kalmanfilter_basics_2.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="index.html" class="icon icon-home"> PythonRobotics + <img src="_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">How To Contribute</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#adding-a-new-algorithm-example">Adding a new algorithm example</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#step-1-choose-an-algorithm-to-implement">Step 1: Choose an algorithm to implement</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step-2-implement-the-algorithm-with-matplotlib-based-animation">Step 2: Implement the algorithm with matplotlib based animation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step-3-add-a-unittest">Step 3: Add a unittest</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step-4-write-a-document-about-the-algorithm">Step 4: Write a document about the algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step-5-submit-a-pull-request-and-fix-codes-based-on-review">Step 5: Submit a pull request and fix codes based on review</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="#reporting-and-fixing-a-defect">Reporting and fixing a defect</a></li> +<li class="toctree-l2"><a class="reference internal" href="#adding-missed-documentations-for-existing-examples">Adding missed documentations for existing examples</a></li> +<li class="toctree-l2"><a class="reference internal" href="#supporting-this-project">Supporting this project</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#sponsors">Sponsors</a></li> +</ul> +</li> +</ul> +</li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="index.html" class="icon icon-home"></a> »</li> + <li>How To Contribute</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/how_to_contribute_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="how-to-contribute"> +<h1>How To Contribute<a class="headerlink" href="#how-to-contribute" title="Permalink to this headline"></a></h1> +<p>This document describes how to contribute this project.</p> +<section id="adding-a-new-algorithm-example"> +<h2>Adding a new algorithm example<a class="headerlink" href="#adding-a-new-algorithm-example" title="Permalink to this headline"></a></h2> +<p>This is a step by step manual to add a new algorithm example.</p> +<section id="step-1-choose-an-algorithm-to-implement"> +<h3>Step 1: Choose an algorithm to implement<a class="headerlink" href="#step-1-choose-an-algorithm-to-implement" title="Permalink to this headline"></a></h3> +<p>Before choosing an algorithm, please check the <a class="reference internal" href="getting_started.html#getting-started"><span class="std std-ref">Getting Started</span></a> doc to +understand this project’s philosophy and setup your development environment.</p> +<p>If an algorithm is widely used and successful, let’s create an issue to +propose it for our community.</p> +<p>If some people agree by thumbs up or posting positive comments, let go to next step.</p> +<p>It is OK to just create an issue to propose adding an algorithm, someone might implement it.</p> +<p>In that case, please share any papers or documentations to implement it.</p> +</section> +<section id="step-2-implement-the-algorithm-with-matplotlib-based-animation"> +<h3>Step 2: Implement the algorithm with matplotlib based animation<a class="headerlink" href="#step-2-implement-the-algorithm-with-matplotlib-based-animation" title="Permalink to this headline"></a></h3> +<p>When you implement an algorithm, please keep the following items in mind.</p> +<ol class="arabic simple"> +<li><p>Use only Python. Other language code is not acceptable.</p></li> +<li><p>This project only accept codes for python 3.9 or higher.</p></li> +<li><p>Use matplotlib based animation to show how the algorithm works.</p></li> +<li><p>Only use current <a class="reference internal" href="getting_started.html#requirements"><span class="std std-ref">Requirements</span></a> libraries, not adding new dependencies.</p></li> +<li><p>Keep simple your code. The main goal is to make it easy for users to understand the algorithm, not for practical usage.</p></li> +</ol> +</section> +<section id="step-3-add-a-unittest"> +<h3>Step 3: Add a unittest<a class="headerlink" href="#step-3-add-a-unittest" title="Permalink to this headline"></a></h3> +<p>If you add a new algorithm sample code, please add a unit test file under <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/tree/master/tests">tests dir</a>.</p> +<p>This sample test code might help you : <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/tests/test_a_star.py">test_a_star.py</a>.</p> +<p>At the least, try to run the example code without animation in the unit test.</p> +<p>If you want to run the test suites locally, you can use the <cite>runtests.sh</cite> script by just executing it.</p> +<p>The <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/tests/test_codestyle.py">test_codestyle.py</a> check code style for your PR’s codes.</p> +</section> +<section id="step-4-write-a-document-about-the-algorithm"> +<span id="how-to-write-doc"></span><h3>Step 4: Write a document about the algorithm<a class="headerlink" href="#step-4-write-a-document-about-the-algorithm" title="Permalink to this headline"></a></h3> +<p>Please add a document to describe the algorithm details, mathematical backgrounds and show graphs and animation gif.</p> +<p>This project is using <a class="reference external" href="https://www.sphinx-doc.org/">Sphinx</a> as a document builder, all documentations are written by <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html">reStructuredText</a>.</p> +<p>You can add a new rst file under the subdirectory in <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/tree/master/docs/modules">doc modules dir</a> and the top rst file can include it.</p> +<p>Please check other documents for details.</p> +<p>You can build the doc locally based on <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/README.md">doc README</a>.</p> +<p>Note that the <a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html">reStructuredText</a> based doc should only focus on the mathematics and the algorithm of the example.</p> +<p>Documentations related codes should be in the python script as the header comments of the script or docstrings of each function.</p> +</section> +<section id="step-5-submit-a-pull-request-and-fix-codes-based-on-review"> +<span id="submit-a-pull-request"></span><h3>Step 5: Submit a pull request and fix codes based on review<a class="headerlink" href="#step-5-submit-a-pull-request-and-fix-codes-based-on-review" title="Permalink to this headline"></a></h3> +<p>Let’s submit a pull request when your code, test, and doc are ready.</p> +<p>At first, please fix all CI errors before code review.</p> +<p>You can check your PR doc from the CI panel.</p> +<p>After the “ci/circleci: build_doc” CI is succeeded, +you can access you PR doc with clicking the [Details] of the “ci/circleci: build_doc artifact” CI.</p> +<img alt="_images/doc_ci.png" src="_images/doc_ci.png" /> +<p>After that, I will start the review.</p> +<p>Note that this is my hobby project; I appreciate your patience during the review process.</p> +</section> +</section> +<section id="reporting-and-fixing-a-defect"> +<h2>Reporting and fixing a defect<a class="headerlink" href="#reporting-and-fixing-a-defect" title="Permalink to this headline"></a></h2> +<p>Reporting and fixing a defect is also great contribution.</p> +<p>When you report an issue, please provide these information:</p> +<ul class="simple"> +<li><p>A clear and concise description of what the bug is.</p></li> +<li><p>A clear and concise description of what you expected to happen.</p></li> +<li><p>Screenshots to help explain your problem if applicable.</p></li> +<li><p>OS version</p></li> +<li><p>Python version</p></li> +<li><p>Each library versions</p></li> +</ul> +<p>If you want to fix any bug, you can find reported issues in <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/issues?q=is%3Aissue+is%3Aopen+label%3Abug">bug labeled issues</a>.</p> +<p>If you fix a bug of existing codes, please add a test function +in the test code to show the issue was solved.</p> +<p>This doc <a class="reference internal" href="#submit-a-pull-request">submit a pull request</a> can be helpful to submit a pull request.</p> +</section> +<section id="adding-missed-documentations-for-existing-examples"> +<h2>Adding missed documentations for existing examples<a class="headerlink" href="#adding-missed-documentations-for-existing-examples" title="Permalink to this headline"></a></h2> +<p>Adding the missed documentations for existing examples is also great contribution.</p> +<p>If you check the <a class="reference external" href="https://atsushisakai.github.io/PythonRobotics">Python Robotics Docs</a>, you can notice that some of the examples +only have a simulation gif or short overview descriptions, +but no detailed algorithm or mathematical description.</p> +<p>This doc <a class="reference internal" href="#how-to-write-doc">how to write doc</a> can be helpful to write documents.</p> +</section> +<section id="supporting-this-project"> +<h2>Supporting this project<a class="headerlink" href="#supporting-this-project" title="Permalink to this headline"></a></h2> +<p>Supporting this project financially is also a great contribution!!.</p> +<p>If you or your company would like to support this project, please consider:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/sponsors/AtsushiSakai">Sponsor @AtsushiSakai on GitHub Sponsors</a></p></li> +<li><p><a class="reference external" href="https://www.patreon.com/myenigma">Become a backer or sponsor on Patreon</a></p></li> +<li><p><a class="reference external" href="https://www.paypal.me/myenigmapay/">One-time donation via PayPal</a></p></li> +</ul> +<p>If you would like to support us in some other way, please contact with creating an issue.</p> +<section id="sponsors"> +<h3>Sponsors<a class="headerlink" href="#sponsors" title="Permalink to this headline"></a></h3> +<ol class="arabic simple"> +<li><p><a class="reference external" href="https://www.jetbrains.com/">JetBrains</a> : They are providing a free license of their IDEs for this OSS development.</p></li> +</ol> +</section> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="modules/appendix/Kalmanfilter_basics_2.html" class="btn btn-neutral float-left" title="KF Basics - Part 2" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000000..0cbb9763bd6 --- /dev/null +++ b/index.html @@ -0,0 +1,279 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Welcome to PythonRobotics’s documentation! — PythonRobotics documentation</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/clipboard.min.js"></script> + <script src="_static/copybutton.js"></script> + <script src="_static/dark_mode_js/default_dark.js"></script> + <script src="_static/dark_mode_js/theme_switcher.js"></script> + <script src="_static/js/theme.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="search.html" /> + <link rel="next" title="Getting Started" href="getting_started.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="#" class="icon icon-home"> PythonRobotics + <img src="_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="#">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="#" class="icon icon-home"></a> »</li> + <li>Welcome to PythonRobotics’s documentation!</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/index_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="welcome-to-pythonrobotics-s-documentation"> +<h1>Welcome to PythonRobotics’s documentation!<a class="headerlink" href="#welcome-to-pythonrobotics-s-documentation" title="Permalink to this headline"></a></h1> +<p>Python codes for robotics algorithm. The project is on <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics">GitHub</a>.</p> +<p>This is a Python code collection of robotics algorithms.</p> +<p>Features:</p> +<ol class="arabic simple"> +<li><p>Easy to read for understanding each algorithm’s basic idea.</p></li> +<li><p>Widely used and practical algorithms are selected.</p></li> +<li><p>Minimum dependency.</p></li> +</ol> +<p>See this paper for more details:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://arxiv.org/abs/1808.10703">[1808.10703] PythonRobotics: a Python code collection of robotics +algorithms</a> (<a class="reference external" href="https://github.com/AtsushiSakai/PythonRoboticsPaper/blob/master/python_robotics.bib">BibTeX</a>)</p></li> +</ul> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a><ul> +<li class="toctree-l2"><a class="reference internal" href="getting_started.html#what-is-this">What is this?</a></li> +<li class="toctree-l2"><a class="reference internal" href="getting_started.html#requirements">Requirements</a></li> +<li class="toctree-l2"><a class="reference internal" href="getting_started.html#how-to-use">How to use</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/introduction.html">Introduction</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#definition-of-robotics">Definition Of Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#history-of-robotics">History Of Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#application-of-robotics">Application Of Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#software-for-robotics">Software for Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#id1">Software for Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#python-for-robotics">Python for Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/introduction.html#learning-robotics-algorithms">Learning Robotics Algorithms</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/localization/localization.html">Localization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/localization/histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/localization/particle_filter_localization/particle_filter_localization.html">Particle filter localization</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/mapping/mapping.html">Mapping</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/mapping/normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/slam/slam.html">SLAM</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/slam/iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/slam/ekf_slam/ekf_slam.html">EKF SLAM</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/slam/FastSLAM1/FastSLAM1.html">FastSLAM1.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/slam/FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/slam/graph_slam/graph_slam.html">Graph based SLAM</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_planning/path_planning.html">Path Planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_planning/coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_tracking/path_tracking.html">Path Tracking</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/path_tracking/cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/arm_navigation/arm_navigation.html">Arm Navigation</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/arm_navigation/planar_two_link_ik.html">Two joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/arm_navigation/n_joint_arm_to_point_control.html">N joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/arm_navigation/obstacle_avoidance_arm_navigation.html">Arm navigation with obstacle avoidance</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following.html">Drone 3d trajectory following</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing.html">Rocket powered landing</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/bipedal/bipedal.html">Bipedal</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/bipedal/bipedal_planner/bipedal_planner.html">Bipedal Planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/control/control.html">Control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/control/inverted_pendulum_control/inverted_pendulum_control.html">Inverted Pendulum Control</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/control/move_to_a_pose_control/move_to_a_pose_control.html">Move to a Pose Control</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/utils/utils.html">Utilities</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/utils/plot/plot.html">Plotting Utilities</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="modules/appendix/appendix.html">Appendix</a><ul> +<li class="toctree-l2"><a class="reference internal" href="modules/appendix/Kalmanfilter_basics.html">KF Basics - Part I</a></li> +<li class="toctree-l2"><a class="reference internal" href="modules/appendix/Kalmanfilter_basics_2.html">KF Basics - Part 2</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="how_to_contribute.html">How To Contribute</a><ul> +<li class="toctree-l2"><a class="reference internal" href="how_to_contribute.html#adding-a-new-algorithm-example">Adding a new algorithm example</a></li> +<li class="toctree-l2"><a class="reference internal" href="how_to_contribute.html#reporting-and-fixing-a-defect">Reporting and fixing a defect</a></li> +<li class="toctree-l2"><a class="reference internal" href="how_to_contribute.html#adding-missed-documentations-for-existing-examples">Adding missed documentations for existing examples</a></li> +<li class="toctree-l2"><a class="reference internal" href="how_to_contribute.html#supporting-this-project">Supporting this project</a></li> +</ul> +</li> +</ul> +</div> +</section> +<section id="indices-and-tables"> +<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1> +<ul class="simple"> +<li><p><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></p></li> +<li><p><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></p></li> +<li><p><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="getting_started.html" class="btn btn-neutral float-right" title="Getting Started" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/aerial_navigation/aerial_navigation.html b/modules/aerial_navigation/aerial_navigation.html new file mode 100644 index 00000000000..65804285240 --- /dev/null +++ b/modules/aerial_navigation/aerial_navigation.html @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Aerial Navigation — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Drone 3d trajectory following" href="drone_3d_trajectory_following/drone_3d_trajectory_following.html" /> + <link rel="prev" title="Arm navigation with obstacle avoidance" href="../arm_navigation/obstacle_avoidance_arm_navigation.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Aerial Navigation</a><ul> +<li class="toctree-l2"><a class="reference internal" href="drone_3d_trajectory_following/drone_3d_trajectory_following.html">Drone 3d trajectory following</a></li> +<li class="toctree-l2"><a class="reference internal" href="rocket_powered_landing/rocket_powered_landing.html">Rocket powered landing</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Aerial Navigation</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/aerial_navigation/aerial_navigation_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="aerial-navigation"> +<span id="id1"></span><h1>Aerial Navigation<a class="headerlink" href="#aerial-navigation" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="drone_3d_trajectory_following/drone_3d_trajectory_following.html">Drone 3d trajectory following</a></li> +<li class="toctree-l1"><a class="reference internal" href="rocket_powered_landing/rocket_powered_landing.html">Rocket powered landing</a><ul> +<li class="toctree-l2"><a class="reference internal" href="rocket_powered_landing/rocket_powered_landing.html#simulation">Simulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="rocket_powered_landing/rocket_powered_landing.html#equation-generation">Equation generation</a></li> +<li class="toctree-l2"><a class="reference internal" href="rocket_powered_landing/rocket_powered_landing.html#references">References</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../arm_navigation/obstacle_avoidance_arm_navigation.html" class="btn btn-neutral float-left" title="Arm navigation with obstacle avoidance" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="drone_3d_trajectory_following/drone_3d_trajectory_following.html" class="btn btn-neutral float-right" title="Drone 3d trajectory following" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following.html b/modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following.html new file mode 100644 index 00000000000..906060e8b88 --- /dev/null +++ b/modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following.html @@ -0,0 +1,148 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Drone 3d trajectory following — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Rocket powered landing" href="../rocket_powered_landing/rocket_powered_landing.html" /> + <link rel="prev" title="Aerial Navigation" href="../aerial_navigation.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../aerial_navigation.html">Aerial Navigation</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Drone 3d trajectory following</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rocket_powered_landing/rocket_powered_landing.html">Rocket powered landing</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../aerial_navigation.html">Aerial Navigation</a> »</li> + <li>Drone 3d trajectory following</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="drone-3d-trajectory-following"> +<h1>Drone 3d trajectory following<a class="headerlink" href="#drone-3d-trajectory-following" title="Permalink to this headline"></a></h1> +<p>This is a 3d trajectory following simulation for a quadrotor.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/AerialNavigation/drone_3d_trajectory_following/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/AerialNavigation/drone_3d_trajectory_following/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../aerial_navigation.html" class="btn btn-neutral float-left" title="Aerial Navigation" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../rocket_powered_landing/rocket_powered_landing.html" class="btn btn-neutral float-right" title="Rocket powered landing" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing.html b/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing.html new file mode 100644 index 00000000000..9988b3515bc --- /dev/null +++ b/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing.html @@ -0,0 +1,272 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Rocket powered landing — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Bipedal" href="../../bipedal/bipedal.html" /> + <link rel="prev" title="Drone 3d trajectory following" href="../drone_3d_trajectory_following/drone_3d_trajectory_following.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../aerial_navigation.html">Aerial Navigation</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../drone_3d_trajectory_following/drone_3d_trajectory_following.html">Drone 3d trajectory following</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Rocket powered landing</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#simulation">Simulation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#equation-generation">Equation generation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../aerial_navigation.html">Aerial Navigation</a> »</li> + <li>Rocket powered landing</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="rocket-powered-landing"> +<h1>Rocket powered landing<a class="headerlink" href="#rocket-powered-landing" title="Permalink to this headline"></a></h1> +<section id="simulation"> +<h2>Simulation<a class="headerlink" href="#simulation" title="Permalink to this headline"></a></h2> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">Image</span> +<span class="n">Image</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">"figure.png"</span><span class="p">,</span><span class="n">width</span><span class="o">=</span><span class="mi">600</span><span class="p">)</span> +<span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">display</span><span class="p">,</span> <span class="n">HTML</span> + +<span class="n">display</span><span class="p">(</span><span class="n">HTML</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="s2">"""</span> +<span class="s2"><style></span> +<span class="s2"> div#notebook-container { width: 95%; }</span> +<span class="s2"> div#menubar-container { width: 65%; }</span> +<span class="s2"> div#maintoolbar-container { width: 99%; }</span> +<span class="s2"></style></span> +<span class="s2">"""</span><span class="p">))</span> +</pre></div> +</div> +<style> + div#notebook-container { width: 95%; } + div#menubar-container { width: 65%; } + div#maintoolbar-container { width: 99%; } +</style><figure class="align-default"> +<img alt="gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/AerialNavigation/rocket_powered_landing/animation.gif" /> +</figure> +</section> +<section id="equation-generation"> +<h2>Equation generation<a class="headerlink" href="#equation-generation" title="Permalink to this headline"></a></h2> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sympy</span> <span class="k">as</span> <span class="nn">sp</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">display</span> +<span class="n">sp</span><span class="o">.</span><span class="n">init_printing</span><span class="p">(</span><span class="n">use_latex</span><span class="o">=</span><span class="s1">'mathjax'</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># parameters</span> +<span class="c1"># Angular moment of inertia</span> +<span class="n">J_B</span> <span class="o">=</span> <span class="mf">1e-2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">1.</span><span class="p">,</span> <span class="mf">1.</span><span class="p">,</span> <span class="mf">1.</span><span class="p">])</span> + +<span class="c1"># Gravity</span> +<span class="n">g_I</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">((</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.</span><span class="p">,</span> <span class="mf">0.</span><span class="p">))</span> + +<span class="c1"># Fuel consumption</span> +<span class="n">alpha_m</span> <span class="o">=</span> <span class="mf">0.01</span> + +<span class="c1"># Vector from thrust point to CoM</span> +<span class="n">r_T_B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">-</span><span class="mf">1e-2</span><span class="p">,</span> <span class="mf">0.</span><span class="p">,</span> <span class="mf">0.</span><span class="p">])</span> + + +<span class="k">def</span> <span class="nf">dir_cosine</span><span class="p">(</span><span class="n">q</span><span class="p">):</span> + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">matrix</span><span class="p">([</span> + <span class="p">[</span><span class="mi">1</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span><span class="p">),</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> + <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]),</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">-</span> <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">])],</span> + <span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">-</span> <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]),</span> <span class="mi">1</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> + <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span><span class="p">),</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">+</span> <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">])],</span> + <span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">+</span> <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">-</span> + <span class="n">q</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="mi">1</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">q</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)]</span> + <span class="p">])</span> + +<span class="k">def</span> <span class="nf">omega</span><span class="p">(</span><span class="n">w</span><span class="p">):</span> + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">matrix</span><span class="p">([</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">w</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="o">-</span><span class="n">w</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="n">w</span><span class="p">[</span><span class="mi">2</span><span class="p">]],</span> + <span class="p">[</span><span class="n">w</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="n">w</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="o">-</span><span class="n">w</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="p">[</span><span class="n">w</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="n">w</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="n">w</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="n">w</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">w</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="n">w</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">])</span> + +<span class="k">def</span> <span class="nf">skew</span><span class="p">(</span><span class="n">v</span><span class="p">):</span> + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">matrix</span><span class="p">([</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">v</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">v</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="p">[</span><span class="n">v</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="o">-</span><span class="n">v</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">]</span> + <span class="p">])</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">f</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + +<span class="n">x</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">Matrix</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">symbols</span><span class="p">(</span> + <span class="s1">'m rx ry rz vx vy vz q0 q1 q2 q3 wx wy wz'</span><span class="p">,</span> <span class="n">real</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span> +<span class="n">u</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">Matrix</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">symbols</span><span class="p">(</span><span class="s1">'ux uy uz'</span><span class="p">,</span> <span class="n">real</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span> + +<span class="n">g_I</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">Matrix</span><span class="p">(</span><span class="n">g_I</span><span class="p">)</span> +<span class="n">r_T_B</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">Matrix</span><span class="p">(</span><span class="n">r_T_B</span><span class="p">)</span> +<span class="n">J_B</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">Matrix</span><span class="p">(</span><span class="n">J_B</span><span class="p">)</span> + +<span class="n">C_B_I</span> <span class="o">=</span> <span class="n">dir_cosine</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">7</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> +<span class="n">C_I_B</span> <span class="o">=</span> <span class="n">C_B_I</span><span class="o">.</span><span class="n">transpose</span><span class="p">()</span> + +<span class="n">f</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span> <span class="n">alpha_m</span> <span class="o">*</span> <span class="n">u</span><span class="o">.</span><span class="n">norm</span><span class="p">()</span> +<span class="n">f</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">7</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> +<span class="n">f</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">7</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">C_I_B</span> <span class="o">*</span> <span class="n">u</span> <span class="o">+</span> <span class="n">g_I</span> +<span class="n">f</span><span class="p">[</span><span class="mi">7</span><span class="p">:</span><span class="mi">11</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">omega</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">11</span><span class="p">:</span><span class="mi">14</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">*</span> <span class="n">x</span><span class="p">[</span><span class="mi">7</span><span class="p">:</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> +<span class="n">f</span><span class="p">[</span><span class="mi">11</span><span class="p">:</span><span class="mi">14</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">J_B</span> <span class="o">**</span> <span class="o">-</span><span class="mi">1</span> <span class="o">*</span> \ + <span class="p">(</span><span class="n">skew</span><span class="p">(</span><span class="n">r_T_B</span><span class="p">)</span> <span class="o">*</span> <span class="n">u</span> <span class="o">-</span> <span class="n">skew</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">11</span><span class="p">:</span><span class="mi">14</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">*</span> <span class="n">J_B</span> <span class="o">*</span> <span class="n">x</span><span class="p">[</span><span class="mi">11</span><span class="p">:</span><span class="mi">14</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">display</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">simplify</span><span class="p">(</span><span class="n">f</span><span class="p">))</span> <span class="c1"># f</span> +</pre></div> +</div> +<div class="math notranslate nohighlight"> +\[\begin{split}\left[\begin{matrix}- 0.01 \sqrt{ux^{2} + uy^{2} + uz^{2}}\\vx\\vy\\vz\\\frac{- 1.0 m - ux \left(2 q_{2}^{2} + 2 q_{3}^{2} - 1\right) - 2 uy \left(q_{0} q_{3} - q_{1} q_{2}\right) + 2 uz \left(q_{0} q_{2} + q_{1} q_{3}\right)}{m}\\\frac{2 ux \left(q_{0} q_{3} + q_{1} q_{2}\right) - uy \left(2 q_{1}^{2} + 2 q_{3}^{2} - 1\right) - 2 uz \left(q_{0} q_{1} - q_{2} q_{3}\right)}{m}\\\frac{- 2 ux \left(q_{0} q_{2} - q_{1} q_{3}\right) + 2 uy \left(q_{0} q_{1} + q_{2} q_{3}\right) - uz \left(2 q_{1}^{2} + 2 q_{2}^{2} - 1\right)}{m}\\- 0.5 q_{1} wx - 0.5 q_{2} wy - 0.5 q_{3} wz\\0.5 q_{0} wx + 0.5 q_{2} wz - 0.5 q_{3} wy\\0.5 q_{0} wy - 0.5 q_{1} wz + 0.5 q_{3} wx\\0.5 q_{0} wz + 0.5 q_{1} wy - 0.5 q_{2} wx\\0\\1.0 uz\\- 1.0 uy\end{matrix}\right]\end{split}\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">display</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">simplify</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">jacobian</span><span class="p">(</span><span class="n">x</span><span class="p">)))</span><span class="c1"># A</span> +</pre></div> +</div> +<div class="math notranslate nohighlight"> +\[\begin{split}\left[\begin{array}{cccccccccccccc}0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\frac{ux \left(2 q_{2}^{2} + 2 q_{3}^{2} - 1\right) + 2 uy \left(q_{0} q_{3} - q_{1} q_{2}\right) - 2 uz \left(q_{0} q_{2} + q_{1} q_{3}\right)}{m^{2}} & 0 & 0 & 0 & 0 & 0 & 0 & \frac{2 \left(q_{2} uz - q_{3} uy\right)}{m} & \frac{2 \left(q_{2} uy + q_{3} uz\right)}{m} & \frac{2 \left(q_{0} uz + q_{1} uy - 2 q_{2} ux\right)}{m} & \frac{2 \left(- q_{0} uy + q_{1} uz - 2 q_{3} ux\right)}{m} & 0 & 0 & 0\\\frac{- 2 ux \left(q_{0} q_{3} + q_{1} q_{2}\right) + uy \left(2 q_{1}^{2} + 2 q_{3}^{2} - 1\right) + 2 uz \left(q_{0} q_{1} - q_{2} q_{3}\right)}{m^{2}} & 0 & 0 & 0 & 0 & 0 & 0 & \frac{2 \left(- q_{1} uz + q_{3} ux\right)}{m} & \frac{2 \left(- q_{0} uz - 2 q_{1} uy + q_{2} ux\right)}{m} & \frac{2 \left(q_{1} ux + q_{3} uz\right)}{m} & \frac{2 \left(q_{0} ux + q_{2} uz - 2 q_{3} uy\right)}{m} & 0 & 0 & 0\\\frac{2 ux \left(q_{0} q_{2} - q_{1} q_{3}\right) - 2 uy \left(q_{0} q_{1} + q_{2} q_{3}\right) + uz \left(2 q_{1}^{2} + 2 q_{2}^{2} - 1\right)}{m^{2}} & 0 & 0 & 0 & 0 & 0 & 0 & \frac{2 \left(q_{1} uy - q_{2} ux\right)}{m} & \frac{2 \left(q_{0} uy - 2 q_{1} uz + q_{3} ux\right)}{m} & \frac{2 \left(- q_{0} ux - 2 q_{2} uz + q_{3} uy\right)}{m} & \frac{2 \left(q_{1} ux + q_{2} uy\right)}{m} & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - 0.5 wx & - 0.5 wy & - 0.5 wz & - 0.5 q_{1} & - 0.5 q_{2} & - 0.5 q_{3}\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0.5 wx & 0 & 0.5 wz & - 0.5 wy & 0.5 q_{0} & - 0.5 q_{3} & 0.5 q_{2}\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0.5 wy & - 0.5 wz & 0 & 0.5 wx & 0.5 q_{3} & 0.5 q_{0} & - 0.5 q_{1}\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0.5 wz & 0.5 wy & - 0.5 wx & 0 & - 0.5 q_{2} & 0.5 q_{1} & 0.5 q_{0}\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\end{array}\right]\end{split}\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">sp</span><span class="o">.</span><span class="n">simplify</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">jacobian</span><span class="p">(</span><span class="n">u</span><span class="p">))</span> <span class="c1"># B</span> +</pre></div> +</div> +<div class="math notranslate nohighlight"> +\[\begin{split}\left[\begin{matrix}- \frac{0.01 ux}{\sqrt{ux^{2} + uy^{2} + uz^{2}}} & - \frac{0.01 uy}{\sqrt{ux^{2} + uy^{2} + uz^{2}}} & - \frac{0.01 uz}{\sqrt{ux^{2} + uy^{2} + uz^{2}}}\\0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\\\frac{- 2 q_{2}^{2} - 2 q_{3}^{2} + 1}{m} & \frac{2 \left(- q_{0} q_{3} + q_{1} q_{2}\right)}{m} & \frac{2 \left(q_{0} q_{2} + q_{1} q_{3}\right)}{m}\\\frac{2 \left(q_{0} q_{3} + q_{1} q_{2}\right)}{m} & \frac{- 2 q_{1}^{2} - 2 q_{3}^{2} + 1}{m} & \frac{2 \left(- q_{0} q_{1} + q_{2} q_{3}\right)}{m}\\\frac{2 \left(- q_{0} q_{2} + q_{1} q_{3}\right)}{m} & \frac{2 \left(q_{0} q_{1} + q_{2} q_{3}\right)}{m} & \frac{- 2 q_{1}^{2} - 2 q_{2}^{2} + 1}{m}\\0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 1.0\\0 & -1.0 & 0\end{matrix}\right]\end{split}\]</div> +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p>Python implementation of ‘Successive Convexification for 6-DoF Mars +Rocket Powered Landing with Free-Final-Time’ paper by Michael Szmuk +and Behçet Açıkmeşe.</p></li> +<li><p>inspired by EmbersArc/SuccessiveConvexificationFreeFinalTime: +Implementation of “Successive Convexification for 6-DoF Mars Rocket +Powered Landing with Free-Final-Time” +<a class="reference external" href="https://github.com/EmbersArc/SuccessiveConvexificationFreeFinalTime">https://github.com/EmbersArc/SuccessiveConvexificationFreeFinalTime</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../drone_3d_trajectory_following/drone_3d_trajectory_following.html" class="btn btn-neutral float-left" title="Drone 3d trajectory following" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../bipedal/bipedal.html" class="btn btn-neutral float-right" title="Bipedal" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/appendix/Kalmanfilter_basics.html b/modules/appendix/Kalmanfilter_basics.html new file mode 100644 index 00000000000..4801fbde548 --- /dev/null +++ b/modules/appendix/Kalmanfilter_basics.html @@ -0,0 +1,576 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>KF Basics - Part I — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="KF Basics - Part 2" href="Kalmanfilter_basics_2.html" /> + <link rel="prev" title="Appendix" href="appendix.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="appendix.html">Appendix</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">KF Basics - Part I</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#introduction">Introduction</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#what-is-the-need-to-describe-belief-in-terms-of-pdfs">What is the need to describe belief in terms of PDF’s?</a></li> +<li class="toctree-l4"><a class="reference internal" href="#what-is-expectation-of-a-random-variables">What is Expectation of a Random Variables?</a></li> +<li class="toctree-l4"><a class="reference internal" href="#what-is-the-advantage-of-representing-the-belief-as-a-unimodal-as-opposed-to-multimodal">What is the advantage of representing the belief as a unimodal as opposed to multimodal?</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#variance-covariance-and-correlation">Variance, Covariance and Correlation</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#variance">Variance</a></li> +<li class="toctree-l4"><a class="reference internal" href="#covariance">Covariance</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#gaussians">Gaussians</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#central-limit-theorem">Central Limit Theorem</a></li> +<li class="toctree-l4"><a class="reference internal" href="#gaussian-distribution">Gaussian Distribution</a></li> +<li class="toctree-l4"><a class="reference internal" href="#why-do-we-need-gaussian-distributions">Why do we need Gaussian distributions?</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#gaussian-properties">Gaussian Properties</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html">KF Basics - Part 2</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li><a href="appendix.html">Appendix</a> »</li> + <li>KF Basics - Part I</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/appendix/Kalmanfilter_basics_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="kf-basics-part-i"> +<h1>KF Basics - Part I<a class="headerlink" href="#kf-basics-part-i" title="Permalink to this headline"></a></h1> +<section id="introduction"> +<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h2> +<section id="what-is-the-need-to-describe-belief-in-terms-of-pdfs"> +<h3>What is the need to describe belief in terms of PDF’s?<a class="headerlink" href="#what-is-the-need-to-describe-belief-in-terms-of-pdfs" title="Permalink to this headline"></a></h3> +<p>This is because robot environments are stochastic. A robot environment +may have cows with Tesla by side. That is a robot and it’s environment +cannot be deterministically modelled(e.g as a function of something like +time t). In the real world sensors are also error prone, and hence +there’ll be a set of values with a mean and variance that it can take. +Hence, we always have to model around some mean and variances +associated.</p> +</section> +<section id="what-is-expectation-of-a-random-variables"> +<h3>What is Expectation of a Random Variables?<a class="headerlink" href="#what-is-expectation-of-a-random-variables" title="Permalink to this headline"></a></h3> +<p>Expectation is nothing but an average of the probabilites</p> +<div class="math notranslate nohighlight"> +\[\mathbb E[X] = \sum_{i=1}^n p_ix_i\]</div> +<p>In the continous form,</p> +<div class="math notranslate nohighlight"> +\[\mathbb E[X] = \int_{-\infty}^\infty x\, f(x) \,dx\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">random</span> +<span class="n">x</span><span class="o">=</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span> +<span class="n">p</span><span class="o">=</span><span class="p">[</span><span class="mf">0.1</span><span class="p">,</span><span class="mf">0.3</span><span class="p">,</span><span class="mf">0.4</span><span class="p">]</span> +<span class="n">E_x</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">multiply</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">p</span><span class="p">))</span> +<span class="nb">print</span><span class="p">(</span><span class="n">E_x</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.4000000000000001</span> +</pre></div> +</div> +</section> +<section id="what-is-the-advantage-of-representing-the-belief-as-a-unimodal-as-opposed-to-multimodal"> +<h3>What is the advantage of representing the belief as a unimodal as opposed to multimodal?<a class="headerlink" href="#what-is-the-advantage-of-representing-the-belief-as-a-unimodal-as-opposed-to-multimodal" title="Permalink to this headline"></a></h3> +<p>Obviously, it makes sense because we can’t multiple probabilities to a +car moving for two locations. This would be too confusing and the +information will not be useful.</p> +</section> +</section> +<section id="variance-covariance-and-correlation"> +<h2>Variance, Covariance and Correlation<a class="headerlink" href="#variance-covariance-and-correlation" title="Permalink to this headline"></a></h2> +<section id="variance"> +<h3>Variance<a class="headerlink" href="#variance" title="Permalink to this headline"></a></h3> +<p>Variance is the spread of the data. The mean does’nt tell much <strong>about</strong> +the data. Therefore the variance tells us about the <strong>story</strong> about the +data meaning the spread of the data.</p> +<div class="math notranslate nohighlight"> +\[\mathit{VAR}(X) = \frac{1}{n}\sum_{i=1}^n (x_i - \mu)^2\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> +<span class="n">np</span><span class="o">.</span><span class="n">var</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.0224618077401504</span> +</pre></div> +</div> +</section> +<section id="covariance"> +<h3>Covariance<a class="headerlink" href="#covariance" title="Permalink to this headline"></a></h3> +<p>This is for a multivariate distribution. For example, a robot in 2-D +space can take values in both x and y. To describe them, a normal +distribution with mean in both x and y is needed.</p> +<p>For a multivariate distribution, mean <span class="math notranslate nohighlight">\(\mu\)</span> can be represented as +a matrix,</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\mu = \begin{bmatrix}\mu_1\\\mu_2\\ \vdots \\\mu_n\end{bmatrix}\end{split}\]</div> +<p>Similarly, variance can also be represented.</p> +<p>But an important concept is that in the same way as every variable or +dimension has a variation in its values, it is also possible that there +will be values on how they <strong>together vary</strong>. This is also a measure of +how two datasets are related to each other or <strong>correlation</strong>.</p> +<p>For example, as height increases weight also generally increases. These +variables are correlated. They are positively correlated because as one +variable gets larger so does the other.</p> +<p>We use a <strong>covariance matrix</strong> to denote covariances of a multivariate +normal distribution:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\Sigma = \begin{bmatrix} + \sigma_1^2 & \sigma_{12} & \cdots & \sigma_{1n} \\ + \sigma_{21} &\sigma_2^2 & \cdots & \sigma_{2n} \\ + \vdots & \vdots & \ddots & \vdots \\ + \sigma_{n1} & \sigma_{n2} & \cdots & \sigma_n^2 + \end{bmatrix}\end{split}\]</div> +<p><strong>Diagonal</strong> - Variance of each variable associated.</p> +<p><strong>Off-Diagonal</strong> - covariance between ith and jth variables.</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned}VAR(X) = \sigma_x^2 &= \frac{1}{n}\sum_{i=1}^n(X - \mu)^2\\ +COV(X, Y) = \sigma_{xy} &= \frac{1}{n}\sum_{i=1}^n[(X-\mu_x)(Y-\mu_y)\big]\end{aligned}\end{split}\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">))</span> +<span class="n">np</span><span class="o">.</span><span class="n">cov</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">array</span><span class="p">([[</span><span class="mf">0.08868895</span><span class="p">,</span> <span class="mf">0.05064471</span><span class="p">,</span> <span class="mf">0.08855629</span><span class="p">],</span> + <span class="p">[</span><span class="mf">0.05064471</span><span class="p">,</span> <span class="mf">0.06219243</span><span class="p">,</span> <span class="mf">0.11555291</span><span class="p">],</span> + <span class="p">[</span><span class="mf">0.08855629</span><span class="p">,</span> <span class="mf">0.11555291</span><span class="p">,</span> <span class="mf">0.21534324</span><span class="p">]])</span> +</pre></div> +</div> +<p>Covariance taking the data as <strong>sample</strong> with <span class="math notranslate nohighlight">\(\frac{1}{N-1}\)</span></p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">x_cor</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">)</span> +<span class="n">y_cor</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">)</span> +<span class="n">np</span><span class="o">.</span><span class="n">cov</span><span class="p">(</span><span class="n">x_cor</span><span class="p">,</span><span class="n">y_cor</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">array</span><span class="p">([[</span> <span class="mf">0.1571437</span> <span class="p">,</span> <span class="o">-</span><span class="mf">0.00766623</span><span class="p">],</span> + <span class="p">[</span><span class="o">-</span><span class="mf">0.00766623</span><span class="p">,</span> <span class="mf">0.13957621</span><span class="p">]])</span> +</pre></div> +</div> +<p>Covariance taking the data as <strong>population</strong> with <span class="math notranslate nohighlight">\(\frac{1}{N}\)</span></p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">np</span><span class="o">.</span><span class="n">cov</span><span class="p">(</span><span class="n">x_cor</span><span class="p">,</span><span class="n">y_cor</span><span class="p">,</span><span class="n">bias</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">array</span><span class="p">([[</span> <span class="mf">0.14142933</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.0068996</span> <span class="p">],</span> + <span class="p">[</span><span class="o">-</span><span class="mf">0.0068996</span> <span class="p">,</span> <span class="mf">0.12561859</span><span class="p">]])</span> +</pre></div> +</div> +</section> +</section> +<section id="gaussians"> +<h2>Gaussians<a class="headerlink" href="#gaussians" title="Permalink to this headline"></a></h2> +<section id="central-limit-theorem"> +<h3>Central Limit Theorem<a class="headerlink" href="#central-limit-theorem" title="Permalink to this headline"></a></h3> +<p>According to this theorem, the average of n samples of random and +independent variables tends to follow a normal distribution as we +increase the sample size.(Generally, for n>=30)</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">import</span> <span class="nn">random</span> +<span class="n">a</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">100</span><span class="p">,))</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">):</span> + <span class="n">x</span><span class="o">=</span><span class="p">[</span><span class="n">random</span><span class="o">.</span><span class="n">uniform</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1000</span><span class="p">)]</span> + <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span><span class="o">/</span><span class="mi">1000</span> +<span class="n">plt</span><span class="o">.</span><span class="n">hist</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="n">array</span><span class="p">([</span> <span class="mf">1.</span><span class="p">,</span> <span class="mf">4.</span><span class="p">,</span> <span class="mf">9.</span><span class="p">,</span> <span class="mf">12.</span><span class="p">,</span> <span class="mf">12.</span><span class="p">,</span> <span class="mf">20.</span><span class="p">,</span> <span class="mf">16.</span><span class="p">,</span> <span class="mf">16.</span><span class="p">,</span> <span class="mf">4.</span><span class="p">,</span> <span class="mf">6.</span><span class="p">]),</span> + <span class="n">array</span><span class="p">([</span><span class="mf">5.30943011</span><span class="p">,</span> <span class="mf">5.34638597</span><span class="p">,</span> <span class="mf">5.38334183</span><span class="p">,</span> <span class="mf">5.42029769</span><span class="p">,</span> <span class="mf">5.45725355</span><span class="p">,</span> + <span class="mf">5.49420941</span><span class="p">,</span> <span class="mf">5.53116527</span><span class="p">,</span> <span class="mf">5.56812114</span><span class="p">,</span> <span class="mf">5.605077</span> <span class="p">,</span> <span class="mf">5.64203286</span><span class="p">,</span> + <span class="mf">5.67898872</span><span class="p">]),</span> + <span class="o"><</span><span class="n">a</span> <span class="nb">list</span> <span class="n">of</span> <span class="mi">10</span> <span class="n">Patch</span> <span class="n">objects</span><span class="o">></span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../_images/Kalmanfilter_basics_14_1.png" src="../../_images/Kalmanfilter_basics_14_1.png" /> +</section> +<section id="gaussian-distribution"> +<h3>Gaussian Distribution<a class="headerlink" href="#gaussian-distribution" title="Permalink to this headline"></a></h3> +<p>A Gaussian is a <em>continuous probability distribution</em> that is completely +described with two parameters, the mean (<span class="math notranslate nohighlight">\(\mu\)</span>) and the variance +(<span class="math notranslate nohighlight">\(\sigma^2\)</span>). It is defined as:</p> +<div class="math notranslate nohighlight"> +\[f(x, \mu, \sigma) = \frac{1}{\sigma\sqrt{2\pi}} \exp\big [{-\frac{(x-\mu)^2}{2\sigma^2} }\big ]\]</div> +<p>Range is <span class="math notranslate nohighlight">\([-\inf,\inf]\)</span></p> +<p>This is just a function of mean(<span class="math notranslate nohighlight">\(\mu\)</span>) and standard deviation +(<span class="math notranslate nohighlight">\(\sigma\)</span>) and what gives the normal distribution the +charecteristic <strong>bell curve</strong>.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">matplotlib.mlab</span> <span class="k">as</span> <span class="nn">mlab</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="kn">import</span> <span class="nn">scipy.stats</span> + +<span class="n">mu</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">variance</span> <span class="o">=</span> <span class="mi">5</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">variance</span><span class="p">)</span> +<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu</span> <span class="o">-</span> <span class="mi">5</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu</span> <span class="o">+</span> <span class="mi">5</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">mu</span><span class="p">,</span> <span class="n">sigma</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../_images/Kalmanfilter_basics_16_0.png" src="../../_images/Kalmanfilter_basics_16_0.png" /> +</section> +<section id="why-do-we-need-gaussian-distributions"> +<h3>Why do we need Gaussian distributions?<a class="headerlink" href="#why-do-we-need-gaussian-distributions" title="Permalink to this headline"></a></h3> +<p>Since it becomes really difficult in the real world to deal with +multimodal distribution as we cannot put the belief in two seperate +location of the robots. This becomes really confusing and in practice +impossible to comprehend. Gaussian probability distribution allows us to +drive the robots using only one mode with peak at the mean with some +variance.</p> +</section> +</section> +<section id="gaussian-properties"> +<h2>Gaussian Properties<a class="headerlink" href="#gaussian-properties" title="Permalink to this headline"></a></h2> +<p><strong>Multiplication</strong></p> +<p>For the measurement update in a Bayes Filter, the algorithm tells us to +multiply the Prior P(X_t) and measurement P(Z_t|X_t) to calculate the +posterior:</p> +<div class="math notranslate nohighlight"> +\[P(X \mid Z) = \frac{P(Z \mid X)P(X)}{P(Z)}\]</div> +<p>Here for the numerator, <span class="math notranslate nohighlight">\(P(Z \mid X),P(X)\)</span> both are gaussian.</p> +<p><span class="math notranslate nohighlight">\(N(\bar\mu, \bar\sigma^1)\)</span> and <span class="math notranslate nohighlight">\(N(\bar\mu, \bar\sigma^2)\)</span> +are their mean and variances.</p> +<p>New mean is</p> +<div class="math notranslate nohighlight"> +\[\mu_\mathtt{new} = \frac{\sigma_z^2\bar\mu + \bar\sigma^2z}{\bar\sigma^2+\sigma_z^2}\]</div> +<p>New variance is</p> +<div class="math notranslate nohighlight"> +\[\sigma_\mathtt{new} = \frac{\sigma_z^2\bar\sigma^2}{\bar\sigma^2+\sigma_z^2}\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">matplotlib.mlab</span> <span class="k">as</span> <span class="nn">mlab</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="n">mu1</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">variance1</span> <span class="o">=</span> <span class="mi">2</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">variance1</span><span class="p">)</span> +<span class="n">x1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu1</span> <span class="o">-</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu1</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">mu1</span><span class="p">,</span> <span class="n">sigma</span><span class="p">),</span><span class="n">label</span><span class="o">=</span><span class="s1">'prior'</span><span class="p">)</span> + +<span class="n">mu2</span> <span class="o">=</span> <span class="mi">10</span> +<span class="n">variance2</span> <span class="o">=</span> <span class="mi">2</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">variance2</span><span class="p">)</span> +<span class="n">x2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu2</span> <span class="o">-</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu2</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span> <span class="n">mu2</span><span class="p">,</span> <span class="n">sigma</span><span class="p">),</span><span class="s2">"g-"</span><span class="p">,</span><span class="n">label</span><span class="o">=</span><span class="s1">'measurement'</span><span class="p">)</span> + + +<span class="n">mu_new</span><span class="o">=</span><span class="p">(</span><span class="n">mu1</span><span class="o">*</span><span class="n">variance2</span><span class="o">+</span><span class="n">mu2</span><span class="o">*</span><span class="n">variance1</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">variance1</span><span class="o">+</span><span class="n">variance2</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"New mean is at: "</span><span class="p">,</span><span class="n">mu_new</span><span class="p">)</span> +<span class="n">var_new</span><span class="o">=</span><span class="p">(</span><span class="n">variance1</span><span class="o">*</span><span class="n">variance2</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">variance1</span><span class="o">+</span><span class="n">variance2</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"New variance is: "</span><span class="p">,</span><span class="n">var_new</span><span class="p">)</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">var_new</span><span class="p">)</span> +<span class="n">x3</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu_new</span> <span class="o">-</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu_new</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x3</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x3</span><span class="p">,</span> <span class="n">mu_new</span><span class="p">,</span> <span class="n">var_new</span><span class="p">),</span><span class="n">label</span><span class="o">=</span><span class="s2">"posterior"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="s1">'upper left'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlim</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">New</span> <span class="n">mean</span> <span class="ow">is</span> <span class="n">at</span><span class="p">:</span> <span class="mf">5.0</span> +<span class="n">New</span> <span class="n">variance</span> <span class="ow">is</span><span class="p">:</span> <span class="mf">1.0</span> +</pre></div> +</div> +<img alt="../../_images/Kalmanfilter_basics_19_1.png" src="../../_images/Kalmanfilter_basics_19_1.png" /> +<p><strong>Addition</strong></p> +<p>The motion step involves a case of adding up probability (Since it has +to abide the Law of Total Probability). This means their beliefs are to +be added and hence two gaussians. They are simply arithmetic additions +of the two.</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{gathered}\mu_x = \mu_p + \mu_z \\ +\sigma_x^2 = \sigma_z^2+\sigma_p^2\, \end{gathered}\end{split}\]</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">matplotlib.mlab</span> <span class="k">as</span> <span class="nn">mlab</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="n">mu1</span> <span class="o">=</span> <span class="mi">5</span> +<span class="n">variance1</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">variance1</span><span class="p">)</span> +<span class="n">x1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu1</span> <span class="o">-</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu1</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">mu1</span><span class="p">,</span> <span class="n">sigma</span><span class="p">),</span><span class="n">label</span><span class="o">=</span><span class="s1">'prior'</span><span class="p">)</span> + +<span class="n">mu2</span> <span class="o">=</span> <span class="mi">10</span> +<span class="n">variance2</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">variance2</span><span class="p">)</span> +<span class="n">x2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu2</span> <span class="o">-</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu2</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span> <span class="n">mu2</span><span class="p">,</span> <span class="n">sigma</span><span class="p">),</span><span class="s2">"g-"</span><span class="p">,</span><span class="n">label</span><span class="o">=</span><span class="s1">'measurement'</span><span class="p">)</span> + + +<span class="n">mu_new</span><span class="o">=</span><span class="n">mu1</span><span class="o">+</span><span class="n">mu2</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"New mean is at: "</span><span class="p">,</span><span class="n">mu_new</span><span class="p">)</span> +<span class="n">var_new</span><span class="o">=</span><span class="p">(</span><span class="n">variance1</span><span class="o">+</span><span class="n">variance2</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"New variance is: "</span><span class="p">,</span><span class="n">var_new</span><span class="p">)</span> +<span class="n">sigma</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">var_new</span><span class="p">)</span> +<span class="n">x3</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">mu_new</span> <span class="o">-</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="n">mu_new</span> <span class="o">+</span> <span class="mi">3</span><span class="o">*</span><span class="n">sigma</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x3</span><span class="p">,</span><span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x3</span><span class="p">,</span> <span class="n">mu_new</span><span class="p">,</span> <span class="n">var_new</span><span class="p">),</span><span class="n">label</span><span class="o">=</span><span class="s2">"posterior"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="s1">'upper left'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlim</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">New</span> <span class="n">mean</span> <span class="ow">is</span> <span class="n">at</span><span class="p">:</span> <span class="mi">15</span> +<span class="n">New</span> <span class="n">variance</span> <span class="ow">is</span><span class="p">:</span> <span class="mi">2</span> +</pre></div> +</div> +<img alt="../../_images/Kalmanfilter_basics_21_1.png" src="../../_images/Kalmanfilter_basics_21_1.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1">#Example from:</span> +<span class="c1">#https://scipython.com/blog/visualizing-the-bivariate-gaussian-distribution/</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">cm</span> +<span class="kn">from</span> <span class="nn">mpl_toolkits.mplot3d</span> <span class="kn">import</span> <span class="n">Axes3D</span> + +<span class="c1"># Our 2-dimensional distribution will be over variables X and Y</span> +<span class="n">N</span> <span class="o">=</span> <span class="mi">60</span> +<span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="n">N</span><span class="p">)</span> +<span class="n">Y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="n">N</span><span class="p">)</span> +<span class="n">X</span><span class="p">,</span> <span class="n">Y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">meshgrid</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span> + +<span class="c1"># Mean vector and covariance matrix</span> +<span class="n">mu</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.</span><span class="p">,</span> <span class="mf">1.</span><span class="p">])</span> +<span class="n">Sigma</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span> <span class="mf">1.</span> <span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">]])</span> + +<span class="c1"># Pack X and Y into a single 3-dimensional array</span> +<span class="n">pos</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">(</span><span class="n">X</span><span class="o">.</span><span class="n">shape</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span><span class="p">,))</span> +<span class="n">pos</span><span class="p">[:,</span> <span class="p">:,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">X</span> +<span class="n">pos</span><span class="p">[:,</span> <span class="p">:,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">Y</span> + +<span class="k">def</span> <span class="nf">multivariate_gaussian</span><span class="p">(</span><span class="n">pos</span><span class="p">,</span> <span class="n">mu</span><span class="p">,</span> <span class="n">Sigma</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""Return the multivariate Gaussian distribution on array pos.</span> + +<span class="sd"> pos is an array constructed by packing the meshed arrays of variables</span> +<span class="sd"> x_1, x_2, x_3, ..., x_k into its _last_ dimension.</span> + +<span class="sd"> """</span> + + <span class="n">n</span> <span class="o">=</span> <span class="n">mu</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">Sigma_det</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">det</span><span class="p">(</span><span class="n">Sigma</span><span class="p">)</span> + <span class="n">Sigma_inv</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">Sigma</span><span class="p">)</span> + <span class="n">N</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">((</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span><span class="o">**</span><span class="n">n</span> <span class="o">*</span> <span class="n">Sigma_det</span><span class="p">)</span> + <span class="c1"># This einsum call calculates (x-mu)T.Sigma-1.(x-mu) in a vectorized</span> + <span class="c1"># way across all the input variables.</span> + <span class="n">fac</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">einsum</span><span class="p">(</span><span class="s1">'...k,kl,...l->...'</span><span class="p">,</span> <span class="n">pos</span><span class="o">-</span><span class="n">mu</span><span class="p">,</span> <span class="n">Sigma_inv</span><span class="p">,</span> <span class="n">pos</span><span class="o">-</span><span class="n">mu</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="n">fac</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">N</span> + +<span class="c1"># The distribution on the variables X, Y packed into pos.</span> +<span class="n">Z</span> <span class="o">=</span> <span class="n">multivariate_gaussian</span><span class="p">(</span><span class="n">pos</span><span class="p">,</span> <span class="n">mu</span><span class="p">,</span> <span class="n">Sigma</span><span class="p">)</span> + +<span class="c1"># Create a surface plot and projected filled contour plot under it.</span> +<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">gca</span><span class="p">(</span><span class="n">projection</span><span class="o">=</span><span class="s1">'3d'</span><span class="p">)</span> +<span class="n">ax</span><span class="o">.</span><span class="n">plot_surface</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">Z</span><span class="p">,</span> <span class="n">rstride</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">cstride</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">antialiased</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> + <span class="n">cmap</span><span class="o">=</span><span class="n">cm</span><span class="o">.</span><span class="n">viridis</span><span class="p">)</span> + +<span class="n">cset</span> <span class="o">=</span> <span class="n">ax</span><span class="o">.</span><span class="n">contourf</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">Z</span><span class="p">,</span> <span class="n">zdir</span><span class="o">=</span><span class="s1">'z'</span><span class="p">,</span> <span class="n">offset</span><span class="o">=-</span><span class="mf">0.15</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="n">cm</span><span class="o">.</span><span class="n">viridis</span><span class="p">)</span> + +<span class="c1"># Adjust the limits, ticks and view angle</span> +<span class="n">ax</span><span class="o">.</span><span class="n">set_zlim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.15</span><span class="p">,</span><span class="mf">0.2</span><span class="p">)</span> +<span class="n">ax</span><span class="o">.</span><span class="n">set_zticks</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mf">0.2</span><span class="p">,</span><span class="mi">5</span><span class="p">))</span> +<span class="n">ax</span><span class="o">.</span><span class="n">view_init</span><span class="p">(</span><span class="mi">27</span><span class="p">,</span> <span class="o">-</span><span class="mi">21</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../_images/Kalmanfilter_basics_22_0.png" src="../../_images/Kalmanfilter_basics_22_0.png" /> +<p>This is a 3D projection of the gaussians involved with the lower surface +showing the 2D projection of the 3D projection above. The innermost +ellipse represents the highest peak, that is the maximum probability for +a given (X,Y) value.</p> +<p>** numpy einsum examples **</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">25</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">)</span> +<span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> +<span class="n">c</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span> <span class="mi">0</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">]</span> + <span class="p">[</span> <span class="mi">5</span> <span class="mi">6</span> <span class="mi">7</span> <span class="mi">8</span> <span class="mi">9</span><span class="p">]</span> + <span class="p">[</span><span class="mi">10</span> <span class="mi">11</span> <span class="mi">12</span> <span class="mi">13</span> <span class="mi">14</span><span class="p">]</span> + <span class="p">[</span><span class="mi">15</span> <span class="mi">16</span> <span class="mi">17</span> <span class="mi">18</span> <span class="mi">19</span><span class="p">]</span> + <span class="p">[</span><span class="mi">20</span> <span class="mi">21</span> <span class="mi">22</span> <span class="mi">23</span> <span class="mi">24</span><span class="p">]]</span> +<span class="p">[</span><span class="mi">0</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">]</span> +<span class="p">[[</span><span class="mi">0</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">]</span> + <span class="p">[</span><span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span><span class="p">]]</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1">#this is the diagonal sum, i repeated means the diagonal</span> +<span class="n">np</span><span class="o">.</span><span class="n">einsum</span><span class="p">(</span><span class="s1">'ij'</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span> +<span class="c1">#this takes the output ii which is the diagonal and outputs to a</span> +<span class="n">np</span><span class="o">.</span><span class="n">einsum</span><span class="p">(</span><span class="s1">'ii->i'</span><span class="p">,</span><span class="n">a</span><span class="p">)</span> +<span class="c1">#this takes in the array A represented by their axes 'ij' and B by its only axes'j'</span> +<span class="c1">#and multiples them element wise</span> +<span class="n">np</span><span class="o">.</span><span class="n">einsum</span><span class="p">(</span><span class="s1">'ij,j'</span><span class="p">,</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">array</span><span class="p">([</span> <span class="mi">30</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="mi">130</span><span class="p">,</span> <span class="mi">180</span><span class="p">,</span> <span class="mi">230</span><span class="p">])</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> +<span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> + <span class="p">[</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">],</span> + <span class="p">[</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">11</span><span class="p">]])</span> +<span class="n">C</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">multiply</span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="n">B</span><span class="p">)</span> +<span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">C</span><span class="p">,</span><span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">array</span><span class="p">([</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">22</span><span class="p">,</span> <span class="mi">76</span><span class="p">])</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">D</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">])</span> +<span class="n">E</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> + <span class="p">[</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">],</span> + <span class="p">[</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">11</span><span class="p">]])</span> + +<span class="n">np</span><span class="o">.</span><span class="n">einsum</span><span class="p">(</span><span class="s1">'i,ij->i'</span><span class="p">,</span><span class="n">D</span><span class="p">,</span><span class="n">E</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">array</span><span class="p">([</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">22</span><span class="p">,</span> <span class="mi">76</span><span class="p">])</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">multivariate_normal</span> +<span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mgrid</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="p">:</span><span class="mi">5</span><span class="p">:</span><span class="mf">.1</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">:</span><span class="mi">5</span><span class="p">:</span><span class="mf">.1</span><span class="p">]</span> +<span class="n">pos</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">shape</span> <span class="o">+</span> <span class="p">(</span><span class="mi">2</span><span class="p">,))</span> +<span class="n">pos</span><span class="p">[:,</span> <span class="p">:,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span> <span class="n">pos</span><span class="p">[:,</span> <span class="p">:,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">y</span> +<span class="n">rv</span> <span class="o">=</span> <span class="n">multivariate_normal</span><span class="p">([</span><span class="mf">0.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.2</span><span class="p">],</span> <span class="p">[[</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.9</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">]])</span> +<span class="n">plt</span><span class="o">.</span><span class="n">contourf</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">rv</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">pos</span><span class="p">))</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="n">matplotlib</span><span class="o">.</span><span class="n">contour</span><span class="o">.</span><span class="n">QuadContourSet</span> <span class="n">at</span> <span class="mh">0x139196438</span><span class="o">></span> +</pre></div> +</div> +<img alt="../../_images/Kalmanfilter_basics_28_1.png" src="../../_images/Kalmanfilter_basics_28_1.png" /> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ol class="arabic simple"> +<li><p>Roger Labbe’s +<a class="reference external" href="https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python">repo</a> +on Kalman Filters. (Majority of the examples in the notes are from +this)</p></li> +<li><p>Probabilistic Robotics by Sebastian Thrun, Wolfram Burgard and Dieter +Fox, MIT Press.</p></li> +<li><p>Scipy +<a class="reference external" href="https://scipython.com/blog/visualizing-the-bivariate-gaussian-distribution/">Documentation</a></p></li> +</ol> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="appendix.html" class="btn btn-neutral float-left" title="Appendix" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="Kalmanfilter_basics_2.html" class="btn btn-neutral float-right" title="KF Basics - Part 2" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/appendix/Kalmanfilter_basics_2.html b/modules/appendix/Kalmanfilter_basics_2.html new file mode 100644 index 00000000000..ea09b3c06e0 --- /dev/null +++ b/modules/appendix/Kalmanfilter_basics_2.html @@ -0,0 +1,414 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>KF Basics - Part 2 — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="How To Contribute" href="../../how_to_contribute.html" /> + <link rel="prev" title="KF Basics - Part I" href="Kalmanfilter_basics.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="appendix.html">Appendix</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html">KF Basics - Part I</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">KF Basics - Part 2</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#probabilistic-generative-laws">Probabilistic Generative Laws</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#st-law">1st Law:</a></li> +<li class="toctree-l4"><a class="reference internal" href="#nd-law">2nd Law:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#conditional-dependence-and-independence-example">Conditional dependence and independence example:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bayes-rule">Bayes Rule:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bayes-filter-algorithm">Bayes Filter Algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bayes-filter-localization-example">Bayes filter localization example:</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bayes-and-kalman-filter-structure">Bayes and Kalman filter structure</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kalman-gain">Kalman Gain</a></li> +<li class="toctree-l3"><a class="reference internal" href="#kalman-filter-univariate-and-multivariate">Kalman Filter - Univariate and Multivariate</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li><a href="appendix.html">Appendix</a> »</li> + <li>KF Basics - Part 2</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/appendix/Kalmanfilter_basics_2_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="kf-basics-part-2"> +<h1>KF Basics - Part 2<a class="headerlink" href="#kf-basics-part-2" title="Permalink to this headline"></a></h1> +<section id="probabilistic-generative-laws"> +<h2>Probabilistic Generative Laws<a class="headerlink" href="#probabilistic-generative-laws" title="Permalink to this headline"></a></h2> +<section id="st-law"> +<h3>1st Law:<a class="headerlink" href="#st-law" title="Permalink to this headline"></a></h3> +<p>The belief representing the state <span class="math notranslate nohighlight">\(x_{t}\)</span>, is conditioned on all +past states, measurements and controls. This can be shown mathematically +by the conditional probability shown below:</p> +<div class="math notranslate nohighlight"> +\[p(x_{t} | x_{0:t-1},z_{1:t-1},u_{1:t})\]</div> +<ol class="arabic simple"> +<li><p><span class="math notranslate nohighlight">\(z_{t}\)</span> represents the <strong>measurement</strong></p></li> +<li><p><span class="math notranslate nohighlight">\(u_{t}\)</span> the <strong>motion command</strong></p></li> +<li><p><span class="math notranslate nohighlight">\(x_{t}\)</span> the <strong>state</strong> (can be the position, velocity, etc) of +the robot or its environment at time t.</p></li> +</ol> +<p>‘If we know the state <span class="math notranslate nohighlight">\(x_{t-1}\)</span> and <span class="math notranslate nohighlight">\(u_{t}\)</span>, then knowing +the states <span class="math notranslate nohighlight">\(x_{0:t-2}\)</span>, <span class="math notranslate nohighlight">\(z_{1:t-1}\)</span> becomes immaterial +through the property of <strong>conditional independence</strong>’. The state +<span class="math notranslate nohighlight">\(x_{t-1}\)</span> introduces a conditional independence between +<span class="math notranslate nohighlight">\(x_{t}\)</span> and <span class="math notranslate nohighlight">\(z_{1:t-1}\)</span>, <span class="math notranslate nohighlight">\(u_{1:t-1}\)</span></p> +<p>Therefore the law now holds as:</p> +<div class="math notranslate nohighlight"> +\[p(x_{t} | x_{0:t-1},z_{1:t-1},u_{1:t})=p(x_{t} | x_{t-1},u_{t})\]</div> +</section> +<section id="nd-law"> +<h3>2nd Law:<a class="headerlink" href="#nd-law" title="Permalink to this headline"></a></h3> +<p>If <span class="math notranslate nohighlight">\(x_{t}\)</span> is complete, then:</p> +<div class="math notranslate nohighlight"> +\[p(z_{t} | x-_{0:t},z_{1:t-1},u_{1:t})=p(z_{t} | x_{t})\]</div> +<p><span class="math notranslate nohighlight">\(x_{t}\)</span> is <strong>complete</strong> means that the past states, controls or +measurements carry no additional information to predict future.</p> +<p><span class="math notranslate nohighlight">\(x_{0:t-1}\)</span>, <span class="math notranslate nohighlight">\(z_{1:t-1}\)</span> and <span class="math notranslate nohighlight">\(u_{1:t}\)</span> are +<strong>conditionally independent</strong> of <span class="math notranslate nohighlight">\(z_{t}\)</span> given <span class="math notranslate nohighlight">\(x_{t}\)</span> of +complete.</p> +<p>The filter works in two parts:</p> +<p><span class="math notranslate nohighlight">\(p(x_{t} | x_{t-1},u_{t})\)</span> -> <strong>State Transition Probability</strong></p> +<p><span class="math notranslate nohighlight">\(p(z_{t} | x_{t})\)</span> -> <strong>Measurement Probability</strong></p> +</section> +</section> +<section id="conditional-dependence-and-independence-example"> +<h2>Conditional dependence and independence example:<a class="headerlink" href="#conditional-dependence-and-independence-example" title="Permalink to this headline"></a></h2> +<p><span class="math notranslate nohighlight">\(\bullet\)</span><strong>Independent but conditionally dependent</strong></p> +<p>Let’s say you flip two fair coins</p> +<p>A - Your first coin flip is heads</p> +<p>B - Your second coin flip is heads</p> +<p>C - Your first two flips were the same</p> +<p>A and B here are independent. However, A and B are conditionally +dependent given C, since if you know C then your first coin flip will +inform the other one.</p> +<p><span class="math notranslate nohighlight">\(\bullet\)</span><strong>Dependent but conditionally independent</strong></p> +<p>A box contains two coins: a regular coin and one fake two-headed coin +((P(H)=1). I choose a coin at random and toss it twice. Define the +following events.</p> +<p>A= First coin toss results in an H.</p> +<p>B= Second coin toss results in an H.</p> +<p>C= Coin 1 (regular) has been selected.</p> +<p>If we know A has occurred (i.e., the first coin toss has resulted in +heads), we would guess that it is more likely that we have chosen Coin 2 +than Coin 1. This in turn increases the conditional probability that B +occurs. This suggests that A and B are not independent. On the other +hand, given C (Coin 1 is selected), A and B are independent.</p> +</section> +<section id="bayes-rule"> +<h2>Bayes Rule:<a class="headerlink" href="#bayes-rule" title="Permalink to this headline"></a></h2> +<p>Posterior =</p> +<div class="math notranslate nohighlight"> +\[\frac{Likelihood*Prior}{Marginal}\]</div> +<p>Here,</p> +<p><strong>Posterior</strong> = Probability of an event occurring based on certain +evidence.</p> +<p><strong>Likelihood</strong> = How probable is the evidence given the event.</p> +<p><strong>Prior</strong> = Probability of the just the event occurring without having +any evidence.</p> +<p><strong>Marginal</strong> = Probability of the evidence given all the instances of +events possible.</p> +<p>Example:</p> +<p>1% of women have breast cancer (and therefore 99% do not). 80% of +mammograms detect breast cancer when it is there (and therefore 20% miss +it). 9.6% of mammograms detect breast cancer when its not there (and +therefore 90.4% correctly return a negative result).</p> +<p>We can turn the process above into an equation, which is Bayes Theorem. +Here is the equation:</p> +<p><span class="math notranslate nohighlight">\(\displaystyle{\Pr(\mathrm{A}|\mathrm{X}) = \frac{\Pr(\mathrm{X}|\mathrm{A})\Pr(\mathrm{A})}{\Pr(\mathrm{X|A})\Pr(\mathrm{A})+ \Pr(\mathrm{X | not \ A})\Pr(\mathrm{not \ A})}}\)</span></p> +<p><span class="math notranslate nohighlight">\(\bullet\)</span>Pr(A|X) = Chance of having cancer (A) given a positive +test (X). This is what we want to know: How likely is it to have cancer +with a positive result? In our case it was 7.8%.</p> +<p><span class="math notranslate nohighlight">\(\bullet\)</span>Pr(X|A) = Chance of a positive test (X) given that you +had cancer (A). This is the chance of a true positive, 80% in our case.</p> +<p><span class="math notranslate nohighlight">\(\bullet\)</span>Pr(A) = Chance of having cancer (1%).</p> +<p><span class="math notranslate nohighlight">\(\bullet\)</span>Pr(not A) = Chance of not having cancer (99%).</p> +<p><span class="math notranslate nohighlight">\(\bullet\)</span>Pr(X|not A) = Chance of a positive test (X) given that +you didn’t have cancer (~A). This is a false positive, 9.6% in our case.</p> +</section> +<section id="bayes-filter-algorithm"> +<h2>Bayes Filter Algorithm<a class="headerlink" href="#bayes-filter-algorithm" title="Permalink to this headline"></a></h2> +<p>The basic filter algorithm is:</p> +<p>for all <span class="math notranslate nohighlight">\(x_{t}\)</span>:</p> +<ol class="arabic simple"> +<li><p><span class="math notranslate nohighlight">\(\overline{bel}(x_t) = \int p(x_t | u_t, x_{t-1}) bel(x_{t-1})dx\)</span></p></li> +<li><p><span class="math notranslate nohighlight">\(bel(x_t) = \eta p(z_t | x_t) \overline{bel}(x_t)\)</span></p></li> +</ol> +<p>end.</p> +<p><span class="math notranslate nohighlight">\(\rightarrow\)</span>The first step in filter is to calculate the prior +for the next step that uses the bayes theorem. This is the +<strong>Prediction</strong> step. The belief, <span class="math notranslate nohighlight">\(\overline{bel}(x_t)\)</span>, is +<strong>before</strong> incorporating measurement(<span class="math notranslate nohighlight">\(z_{t}\)</span>) at time t=t. This +is the step where the motion occurs and information is lost because the +means and covariances of the gaussians are added. The RHS of the +equation incorporates the law of total probability for prior +calculation.</p> +<p><span class="math notranslate nohighlight">\(\rightarrow\)</span> This is the <strong>Correction</strong> or update step that +calculates the belief of the robot <strong>after</strong> taking into account the +measurement(<span class="math notranslate nohighlight">\(z_{t}\)</span>) at time t=t. This is where we incorporate +the sensor information for the whereabouts of the robot. We gain +information here as the gaussians get multiplied here. (Multiplication +of gaussian values allows the resultant to lie in between these numbers +and the resultant covariance is smaller.</p> +</section> +<section id="bayes-filter-localization-example"> +<h2>Bayes filter localization example:<a class="headerlink" href="#bayes-filter-localization-example" title="Permalink to this headline"></a></h2> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">Image</span> +<span class="n">Image</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">"bayes_filter.png"</span><span class="p">,</span><span class="n">width</span><span class="o">=</span><span class="mi">400</span><span class="p">)</span> +</pre></div> +</div> +<a class="reference internal image-reference" href="../../_images/Kalmanfilter_basics_2_5_0.png"><img alt="../../_images/Kalmanfilter_basics_2_5_0.png" src="../../_images/Kalmanfilter_basics_2_5_0.png" style="width: 400px;" /></a> +<p>Given - A robot with a sensor to detect doorways along a hallway. Also, +the robot knows how the hallway looks like but doesn’t know where it is +in the map.</p> +<ol class="arabic simple"> +<li><p>Initially(first scenario), it doesn’t know where it is with respect +to the map and hence the belief assigns equal probability to each +location in the map.</p></li> +<li><p>The first sensor reading is incorporated and it shows the presence of +a door. Now the robot knows how the map looks like but cannot +localize yet as map has 3 doors present. Therefore it assigns equal +probability to each door present.</p></li> +<li><p>The robot now moves forward. This is the prediction step and the +motion causes the robot to lose some of the information and hence the +variance of the gaussians increase (diagram 4.). The final belief is +<strong>convolution</strong> of posterior from previous step and the current state +after motion. Also, the means shift on the right due to the motion.</p></li> +<li><p>Again, incorporating the measurement, the sensor senses a door and +this time too the possibility of door is equal for the three door. +This is where the filter’s magic kicks in. For the final belief +(diagram 5.), the posterior calculated after sensing is mixed or +<strong>convolution</strong> of previous posterior and measurement. It improves +the robot’s belief at location near to the second door. The variance +<strong>decreases</strong> and <strong>peaks</strong>.</p></li> +<li><p>Finally after series of iterations of motion and correction, the +robot is able to localize itself with respect to the +environment.(diagram 6.)</p></li> +</ol> +<p>Do note that the robot knows the map but doesn’t know where exactly it +is on the map.</p> +</section> +<section id="bayes-and-kalman-filter-structure"> +<h2>Bayes and Kalman filter structure<a class="headerlink" href="#bayes-and-kalman-filter-structure" title="Permalink to this headline"></a></h2> +<p>The basic structure and the concept remains the same as bayes filter for +Kalman. The only key difference is the mathematical representation of +Kalman filter. The Kalman filter is nothing but a bayesian filter that +uses Gaussians.</p> +<p>For a bayes filter to be a Kalman filter, <strong>each term of belief is now a +gaussian</strong>, unlike histograms. The basic formulation for the <strong>bayes +filter</strong> algorithm is:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} +\bar {\mathbf x} &= \mathbf x \ast f_{\mathbf x}(\bullet)\, \, &\text{Prediction} \\ +\mathbf x &= \mathcal L \cdot \bar{\mathbf x}\, \, &\text{Correction} +\end{aligned}\end{split}\]</div> +<p><span class="math notranslate nohighlight">\(\bar{\mathbf x}\)</span> is the <em>prior</em></p> +<p><span class="math notranslate nohighlight">\(\mathcal L\)</span> is the <em>likelihood</em> of a measurement given the prior +<span class="math notranslate nohighlight">\(\bar{\mathbf x}\)</span></p> +<p><span class="math notranslate nohighlight">\(f_{\mathbf x}(\bullet)\)</span> is the <em>process model</em> or the gaussian +term that helps predict the next state like velocity to track position +or acceleration.</p> +<p><span class="math notranslate nohighlight">\(\ast\)</span> denotes <em>convolution</em>.</p> +</section> +<section id="kalman-gain"> +<h2>Kalman Gain<a class="headerlink" href="#kalman-gain" title="Permalink to this headline"></a></h2> +<div class="math notranslate nohighlight"> +\[x = (\mathcal L \bar x)\]</div> +<p>Where x is posterior and <span class="math notranslate nohighlight">\(\mathcal L\)</span> and <span class="math notranslate nohighlight">\(\bar x\)</span> are +gaussians.</p> +<p>Therefore the mean of the posterior is given by:</p> +<div class="math notranslate nohighlight"> +\[\mu=\frac{\bar\sigma^2\, \mu_z + \sigma_z^2 \, \bar\mu} {\bar\sigma^2 + \sigma_z^2}\]</div> +<div class="math notranslate nohighlight"> +\[\mu = \left( \frac{\bar\sigma^2}{\bar\sigma^2 + \sigma_z^2}\right) \mu_z + \left(\frac{\sigma_z^2}{\bar\sigma^2 + \sigma_z^2}\right)\bar\mu\]</div> +<p>In this form it is easy to see that we are scaling the measurement and +the prior by weights:</p> +<div class="math notranslate nohighlight"> +\[\mu = W_1 \mu_z + W_2 \bar\mu\]</div> +<p>The weights sum to one because the denominator is a normalization term. +We introduce a new term, <span class="math notranslate nohighlight">\(K=W_1\)</span>, giving us:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} +\mu &= K \mu_z + (1-K) \bar\mu\\ +&= \bar\mu + K(\mu_z - \bar\mu) +\end{aligned}\end{split}\]</div> +<p>where</p> +<div class="math notranslate nohighlight"> +\[K = \frac {\bar\sigma^2}{\bar\sigma^2 + \sigma_z^2}\]</div> +<p>The variance in terms of the Kalman gain:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} +\sigma^2 &= \frac{\bar\sigma^2 \sigma_z^2 } {\bar\sigma^2 + \sigma_z^2} \\ +&= K\sigma_z^2 \\ +&= (1-K)\bar\sigma^2 +\end{aligned}\end{split}\]</div> +<p><span class="math notranslate nohighlight">\(K\)</span> is the <em>Kalman gain</em>. It’s the crux of the Kalman filter. It +is a scaling term that chooses a value partway between <span class="math notranslate nohighlight">\(\mu_z\)</span> and +<span class="math notranslate nohighlight">\(\bar\mu\)</span>.</p> +</section> +<section id="kalman-filter-univariate-and-multivariate"> +<h2>Kalman Filter - Univariate and Multivariate<a class="headerlink" href="#kalman-filter-univariate-and-multivariate" title="Permalink to this headline"></a></h2> +<p><strong>Prediction</strong></p> +<p><span class="math notranslate nohighlight">\(\begin{array}{|l|l|l|} \hline \text{Univariate} & \text{Univariate} & \text{Multivariate}\\ & \text{(Kalman form)} & \\ \hline \bar \mu = \mu + \mu_{f_x} & \bar x = x + dx & \bar{\mathbf x} = \mathbf{Fx} + \mathbf{Bu}\\ \bar\sigma^2 = \sigma_x^2 + \sigma_{f_x}^2 & \bar P = P + Q & \bar{\mathbf P} = \mathbf{FPF}^\mathsf T + \mathbf Q \\ \hline \end{array}\)</span></p> +<p><span class="math notranslate nohighlight">\(\mathbf x,\, \mathbf P\)</span> are the state mean and covariance. They +correspond to <span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(\sigma^2\)</span>.</p> +<p><span class="math notranslate nohighlight">\(\mathbf F\)</span> is the <em>state transition function</em>. When multiplied by +<span class="math notranslate nohighlight">\(\bf x\)</span> it computes the prior.</p> +<p><span class="math notranslate nohighlight">\(\mathbf Q\)</span> is the process covariance. It corresponds to +<span class="math notranslate nohighlight">\(\sigma^2_{f_x}\)</span>.</p> +<p><span class="math notranslate nohighlight">\(\mathbf B\)</span> and <span class="math notranslate nohighlight">\(\mathbf u\)</span> are model control inputs to the +system.</p> +<p><strong>Correction</strong></p> +<p><span class="math notranslate nohighlight">\(\begin{array}{|l|l|l|} \hline \text{Univariate} & \text{Univariate} & \text{Multivariate}\\ & \text{(Kalman form)} & \\ \hline & y = z - \bar x & \mathbf y = \mathbf z - \mathbf{H\bar x} \\ & K = \frac{\bar P}{\bar P+R}& \mathbf K = \mathbf{\bar{P}H}^\mathsf T (\mathbf{H\bar{P}H}^\mathsf T + \mathbf R)^{-1} \\ \mu=\frac{\bar\sigma^2\, \mu_z + \sigma_z^2 \, \bar\mu} {\bar\sigma^2 + \sigma_z^2} & x = \bar x + Ky & \mathbf x = \bar{\mathbf x} + \mathbf{Ky} \\ \sigma^2 = \frac{\sigma_1^2\sigma_2^2}{\sigma_1^2+\sigma_2^2} & P = (1-K)\bar P & \mathbf P = (\mathbf I - \mathbf{KH})\mathbf{\bar{P}} \\ \hline \end{array}\)</span></p> +<p><span class="math notranslate nohighlight">\(\mathbf H\)</span> is the measurement function.</p> +<p><span class="math notranslate nohighlight">\(\mathbf z,\, \mathbf R\)</span> are the measurement mean and noise +covariance. They correspond to <span class="math notranslate nohighlight">\(z\)</span> and <span class="math notranslate nohighlight">\(\sigma_z^2\)</span> in the +univariate filter. <span class="math notranslate nohighlight">\(\mathbf y\)</span> and <span class="math notranslate nohighlight">\(\mathbf K\)</span> are the +residual and Kalman gain.</p> +<p>The details will be different than the univariate filter because these +are vectors and matrices, but the concepts are exactly the same:</p> +<ul class="simple"> +<li><p>Use a Gaussian to represent our estimate of the state and error</p></li> +<li><p>Use a Gaussian to represent the measurement and its error</p></li> +<li><p>Use a Gaussian to represent the process model</p></li> +<li><p>Use the process model to predict the next state (the prior)</p></li> +<li><p>Form an estimate part way between the measurement and the prior</p></li> +</ul> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ol class="arabic simple"> +<li><p>Roger Labbe’s +<a class="reference external" href="https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python">repo</a> +on Kalman Filters. (Majority of text in the notes are from this)</p></li> +<li><p>Probabilistic Robotics by Sebastian Thrun, Wolfram Burgard and Dieter +Fox, MIT Press.</p></li> +</ol> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="Kalmanfilter_basics.html" class="btn btn-neutral float-left" title="KF Basics - Part I" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../how_to_contribute.html" class="btn btn-neutral float-right" title="How To Contribute" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/appendix/appendix.html b/modules/appendix/appendix.html new file mode 100644 index 00000000000..9ef705b7a69 --- /dev/null +++ b/modules/appendix/appendix.html @@ -0,0 +1,170 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Appendix — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="KF Basics - Part I" href="Kalmanfilter_basics.html" /> + <link rel="prev" title="Plotting Utilities" href="../utils/plot/plot.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Appendix</a><ul> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html">KF Basics - Part I</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html">KF Basics - Part 2</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Appendix</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/appendix/appendix_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="appendix"> +<span id="id1"></span><h1>Appendix<a class="headerlink" href="#appendix" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="Kalmanfilter_basics.html">KF Basics - Part I</a><ul> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html#introduction">Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html#variance-covariance-and-correlation">Variance, Covariance and Correlation</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html#gaussians">Gaussians</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html#gaussian-properties">Gaussian Properties</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="Kalmanfilter_basics_2.html">KF Basics - Part 2</a><ul> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#probabilistic-generative-laws">Probabilistic Generative Laws</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#conditional-dependence-and-independence-example">Conditional dependence and independence example:</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#bayes-rule">Bayes Rule:</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#bayes-filter-algorithm">Bayes Filter Algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#bayes-filter-localization-example">Bayes filter localization example:</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#bayes-and-kalman-filter-structure">Bayes and Kalman filter structure</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#kalman-gain">Kalman Gain</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#kalman-filter-univariate-and-multivariate">Kalman Filter - Univariate and Multivariate</a></li> +<li class="toctree-l2"><a class="reference internal" href="Kalmanfilter_basics_2.html#references">References:</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../utils/plot/plot.html" class="btn btn-neutral float-left" title="Plotting Utilities" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="Kalmanfilter_basics.html" class="btn btn-neutral float-right" title="KF Basics - Part I" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/arm_navigation/arm_navigation.html b/modules/arm_navigation/arm_navigation.html new file mode 100644 index 00000000000..ce8a99c1306 --- /dev/null +++ b/modules/arm_navigation/arm_navigation.html @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Arm Navigation — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Two joint arm to point control" href="planar_two_link_ik.html" /> + <link rel="prev" title="Nonlinear Model Predictive Control with C-GMRES" href="../path_tracking/cgmres_nmpc/cgmres_nmpc.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Arm Navigation</a><ul> +<li class="toctree-l2"><a class="reference internal" href="planar_two_link_ik.html">Two joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="n_joint_arm_to_point_control.html">N joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="obstacle_avoidance_arm_navigation.html">Arm navigation with obstacle avoidance</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Arm Navigation</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/arm_navigation/arm_navigation_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="arm-navigation"> +<span id="id1"></span><h1>Arm Navigation<a class="headerlink" href="#arm-navigation" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="planar_two_link_ik.html">Two joint arm to point control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="planar_two_link_ik.html#inverse-kinematics-for-a-planar-two-link-robotic-arm">Inverse Kinematics for a Planar Two-Link Robotic Arm</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="n_joint_arm_to_point_control.html">N joint arm to point control</a></li> +<li class="toctree-l1"><a class="reference internal" href="obstacle_avoidance_arm_navigation.html">Arm navigation with obstacle avoidance</a></li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../path_tracking/cgmres_nmpc/cgmres_nmpc.html" class="btn btn-neutral float-left" title="Nonlinear Model Predictive Control with C-GMRES" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="planar_two_link_ik.html" class="btn btn-neutral float-right" title="Two joint arm to point control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/arm_navigation/n_joint_arm_to_point_control.html b/modules/arm_navigation/n_joint_arm_to_point_control.html new file mode 100644 index 00000000000..d903f41397b --- /dev/null +++ b/modules/arm_navigation/n_joint_arm_to_point_control.html @@ -0,0 +1,153 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>N joint arm to point control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Arm navigation with obstacle avoidance" href="obstacle_avoidance_arm_navigation.html" /> + <link rel="prev" title="Two joint arm to point control" href="planar_two_link_ik.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="arm_navigation.html">Arm Navigation</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="planar_two_link_ik.html">Two joint arm to point control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">N joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="obstacle_avoidance_arm_navigation.html">Arm navigation with obstacle avoidance</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li><a href="arm_navigation.html">Arm Navigation</a> »</li> + <li>N joint arm to point control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/arm_navigation/n_joint_arm_to_point_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="n-joint-arm-to-point-control"> +<h1>N joint arm to point control<a class="headerlink" href="#n-joint-arm-to-point-control" title="Permalink to this headline"></a></h1> +<p>N joint arm to a point control simulation.</p> +<p>This is a interactive simulation.</p> +<p>You can set the goal position of the end effector with left-click on the +plotting area.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/ArmNavigation/n_joint_arm_to_point_control/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/ArmNavigation/n_joint_arm_to_point_control/animation.gif" /> +<p>In this simulation N = 10, however, you can change it.</p> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="planar_two_link_ik.html" class="btn btn-neutral float-left" title="Two joint arm to point control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="obstacle_avoidance_arm_navigation.html" class="btn btn-neutral float-right" title="Arm navigation with obstacle avoidance" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/arm_navigation/obstacle_avoidance_arm_navigation.html b/modules/arm_navigation/obstacle_avoidance_arm_navigation.html new file mode 100644 index 00000000000..b5b7bcd5cd0 --- /dev/null +++ b/modules/arm_navigation/obstacle_avoidance_arm_navigation.html @@ -0,0 +1,149 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Arm navigation with obstacle avoidance — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Aerial Navigation" href="../aerial_navigation/aerial_navigation.html" /> + <link rel="prev" title="N joint arm to point control" href="n_joint_arm_to_point_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="arm_navigation.html">Arm Navigation</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="planar_two_link_ik.html">Two joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="n_joint_arm_to_point_control.html">N joint arm to point control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Arm navigation with obstacle avoidance</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li><a href="arm_navigation.html">Arm Navigation</a> »</li> + <li>Arm navigation with obstacle avoidance</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/arm_navigation/obstacle_avoidance_arm_navigation_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="arm-navigation-with-obstacle-avoidance"> +<h1>Arm navigation with obstacle avoidance<a class="headerlink" href="#arm-navigation-with-obstacle-avoidance" title="Permalink to this headline"></a></h1> +<p>Arm navigation with obstacle avoidance simulation.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/ArmNavigation/arm_obstacle_navigation/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/ArmNavigation/arm_obstacle_navigation/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="n_joint_arm_to_point_control.html" class="btn btn-neutral float-left" title="N joint arm to point control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../aerial_navigation/aerial_navigation.html" class="btn btn-neutral float-right" title="Aerial Navigation" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/arm_navigation/planar_two_link_ik.html b/modules/arm_navigation/planar_two_link_ik.html new file mode 100644 index 00000000000..f4852440cfa --- /dev/null +++ b/modules/arm_navigation/planar_two_link_ik.html @@ -0,0 +1,447 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Two joint arm to point control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="N joint arm to point control" href="n_joint_arm_to_point_control.html" /> + <link rel="prev" title="Arm Navigation" href="arm_navigation.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="arm_navigation.html">Arm Navigation</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Two joint arm to point control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#inverse-kinematics-for-a-planar-two-link-robotic-arm">Inverse Kinematics for a Planar Two-Link Robotic Arm</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="n_joint_arm_to_point_control.html">N joint arm to point control</a></li> +<li class="toctree-l2"><a class="reference internal" href="obstacle_avoidance_arm_navigation.html">Arm navigation with obstacle avoidance</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li><a href="arm_navigation.html">Arm Navigation</a> »</li> + <li>Two joint arm to point control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/arm_navigation/planar_two_link_ik_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="two-joint-arm-to-point-control"> +<h1>Two joint arm to point control<a class="headerlink" href="#two-joint-arm-to-point-control" title="Permalink to this headline"></a></h1> +<figure class="align-default"> +<img alt="TwoJointArmToPointControl" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/ArmNavigation/two_joint_arm_to_point_control/animation.gif" /> +</figure> +<p>This is two joint arm to a point control simulation.</p> +<p>This is a interactive simulation.</p> +<p>You can set the goal position of the end effector with left-click on the plotting area.</p> +<section id="inverse-kinematics-for-a-planar-two-link-robotic-arm"> +<h2>Inverse Kinematics for a Planar Two-Link Robotic Arm<a class="headerlink" href="#inverse-kinematics-for-a-planar-two-link-robotic-arm" title="Permalink to this headline"></a></h2> +<p>A classic problem with robotic arms is getting the end-effector, the +mechanism at the end of the arm responsible for manipulating the +environment, to where you need it to be. Maybe the end-effector is a +gripper and maybe you want to pick up an object and maybe you know where +that object is relative to the robot - but you cannot tell the +end-effector where to go directly. Instead, you have to determine the +joint angles that get the end-effector to where you want it to be. This +problem is known as inverse kinematics.</p> +<p>Credit for this solution goes to: +<a class="reference external" href="https://robotacademy.net.au/lesson/inverse-kinematics-for-a-2-joint-robot-arm-using-geometry/">https://robotacademy.net.au/lesson/inverse-kinematics-for-a-2-joint-robot-arm-using-geometry/</a></p> +<p>First, let’s define a class to make plotting our arm easier.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="o">%</span><span class="k">matplotlib</span> inline +<span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">cos</span><span class="p">,</span> <span class="n">sin</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> + +<span class="k">class</span> <span class="nc">TwoLinkArm</span><span class="p">:</span> + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">joint_angles</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">shoulder</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">link_lengths</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">update_joints</span><span class="p">(</span><span class="n">joint_angles</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">update_joints</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">joint_angles</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">joint_angles</span> <span class="o">=</span> <span class="n">joint_angles</span> + <span class="bp">self</span><span class="o">.</span><span class="n">forward_kinematics</span><span class="p">()</span> + + <span class="k">def</span> <span class="nf">forward_kinematics</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">theta0</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">joint_angles</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">theta1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">joint_angles</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> + <span class="n">l0</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_lengths</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">l1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_lengths</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> + <span class="bp">self</span><span class="o">.</span><span class="n">elbow</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shoulder</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">l0</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">theta0</span><span class="p">),</span> <span class="n">l0</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">theta0</span><span class="p">)])</span> + <span class="bp">self</span><span class="o">.</span><span class="n">wrist</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">elbow</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">l1</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">theta0</span> <span class="o">+</span> <span class="n">theta1</span><span class="p">),</span> <span class="n">l1</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">theta0</span> <span class="o">+</span> <span class="n">theta1</span><span class="p">)])</span> + + <span class="k">def</span> <span class="nf">plot</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">shoulder</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">shoulder</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'r-'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'r-'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">shoulder</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">shoulder</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s1">'ko'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s1">'ko'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s1">'ko'</span><span class="p">)</span> +</pre></div> +</div> +<p>Let’s also define a function to make it easier to draw an angle on our +diagram.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">sqrt</span> + +<span class="k">def</span> <span class="nf">transform_points</span><span class="p">(</span><span class="n">points</span><span class="p">,</span> <span class="n">theta</span><span class="p">,</span> <span class="n">origin</span><span class="p">):</span> + <span class="n">T</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="o">-</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="n">origin</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span> <span class="n">origin</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]])</span> + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">matmul</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">points</span><span class="p">))</span> + +<span class="k">def</span> <span class="nf">draw_angle</span><span class="p">(</span><span class="n">angle</span><span class="p">,</span> <span class="n">offset</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">n_points</span><span class="o">=</span><span class="mi">100</span><span class="p">):</span> + <span class="n">x_start</span> <span class="o">=</span> <span class="n">r</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">angle</span><span class="p">)</span> + <span class="n">x_end</span> <span class="o">=</span> <span class="n">r</span> + <span class="n">dx</span> <span class="o">=</span> <span class="p">(</span><span class="n">x_end</span> <span class="o">-</span> <span class="n">x_start</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">n_points</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> + <span class="n">coords</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">0</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n_points</span><span class="p">)]</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)]</span> + <span class="n">x</span> <span class="o">=</span> <span class="n">x_start</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n_points</span><span class="o">-</span><span class="mi">1</span><span class="p">):</span> + <span class="n">y</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">r</span><span class="o">**</span><span class="mi">2</span> <span class="o">-</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> + <span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span> + <span class="n">coords</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">y</span> + <span class="n">coords</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> + <span class="n">x</span> <span class="o">+=</span> <span class="n">dx</span> + <span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">r</span> + <span class="n">coords</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> + <span class="n">coords</span> <span class="o">=</span> <span class="n">transform_points</span><span class="p">(</span><span class="n">coords</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">origin</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">coords</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s1">'k-'</span><span class="p">)</span> +</pre></div> +</div> +<p>Okay, we now have a TwoLinkArm class to help us draw the arm, which +we’ll do several times during our derivation. Notice there is a method +called forward_kinematics - forward kinematics specifies the +end-effector position given the joint angles and link lengths. Forward +kinematics is easier than inverse kinematics.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">arm</span> <span class="o">=</span> <span class="n">TwoLinkArm</span><span class="p">()</span> + +<span class="n">theta0</span> <span class="o">=</span> <span class="mf">0.5</span> +<span class="n">theta1</span> <span class="o">=</span> <span class="mi">1</span> + +<span class="n">arm</span><span class="o">.</span><span class="n">update_joints</span><span class="p">([</span><span class="n">theta0</span><span class="p">,</span> <span class="n">theta1</span><span class="p">])</span> +<span class="n">arm</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> + +<span class="k">def</span> <span class="nf">label_diagram</span><span class="p">():</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="s1">'k--'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="mf">0.5</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">theta0</span><span class="p">)],</span> + <span class="p">[</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="mf">0.5</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">theta0</span><span class="p">)],</span> + <span class="s1">'k--'</span><span class="p">)</span> + + <span class="n">draw_angle</span><span class="p">(</span><span class="n">theta0</span><span class="p">,</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span> + <span class="n">draw_angle</span><span class="p">(</span><span class="n">theta1</span><span class="p">,</span> <span class="n">offset</span><span class="o">=</span><span class="n">theta0</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="p">[</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$l_0$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"r"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$l_1$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.8</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"r"</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$\theta_0$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.35</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$\theta_1$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> + +<span class="n">label_diagram</span><span class="p">()</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"Shoulder"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="n">arm</span><span class="o">.</span><span class="n">shoulder</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">shoulder</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="mf">0.15</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">),</span> + <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">facecolor</span><span class="o">=</span><span class="s1">'black'</span><span class="p">,</span> <span class="n">shrink</span><span class="o">=</span><span class="mf">0.05</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"Elbow"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="mf">1.25</span><span class="p">,</span> <span class="mf">0.25</span><span class="p">),</span> + <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">facecolor</span><span class="o">=</span><span class="s1">'black'</span><span class="p">,</span> <span class="n">shrink</span><span class="o">=</span><span class="mf">0.05</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"Wrist"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.75</span><span class="p">),</span> + <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">facecolor</span><span class="o">=</span><span class="s1">'black'</span><span class="p">,</span> <span class="n">shrink</span><span class="o">=</span><span class="mf">0.05</span><span class="p">))</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../_images/Planar_Two_Link_IK_5_0.png" src="../../_images/Planar_Two_Link_IK_5_0.png" /> +<p>It’s common to name arm joints anatomically, hence the names shoulder, +elbow, and wrist. In this example, the wrist is not itself a joint, but +we can consider it to be our end-effector. If we constrain the shoulder +to the origin, we can write the forward kinematics for the elbow and the +wrist.</p> +<div class="line-block"> +<div class="line"><span class="math notranslate nohighlight">\(elbow_x = l_0\cos(\theta_0)\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(elbow_y = l_0\sin(\theta_0)\)</span></div> +</div> +<div class="line-block"> +<div class="line"><span class="math notranslate nohighlight">\(wrist_x = elbow_x + l_1\cos(\theta_0+\theta_1) = l_0\cos(\theta_0) + l_1\cos(\theta_0+\theta_1)\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(wrist_y = elbow_y + l_1\sin(\theta_0+\theta_1) = l_0\sin(\theta_0) + l_1\sin(\theta_0+\theta_1)\)</span></div> +</div> +<p>Since the wrist is our end-effector, let’s just call its coordinates +<span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span>. The forward kinematics for our +end-effector is then</p> +<div class="line-block"> +<div class="line"><span class="math notranslate nohighlight">\(x = l_0\cos(\theta_0) + l_1\cos(\theta_0+\theta_1)\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(y = l_0\sin(\theta_0) + l_1\sin(\theta_0+\theta_1)\)</span></div> +</div> +<p>A first attempt to find the joint angles <span class="math notranslate nohighlight">\(\theta_0\)</span> and +<span class="math notranslate nohighlight">\(\theta_1\)</span> that would get our end-effector to the desired +coordinates <span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span> might be to try solving the forward +kinematics for <span class="math notranslate nohighlight">\(\theta_0\)</span> and <span class="math notranslate nohighlight">\(\theta_1\)</span>, but that would be +the wrong move. An easier path involves going back to the geometry of +the arm.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">pi</span> + +<span class="n">arm</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> +<span class="n">label_diagram</span><span class="p">()</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'k--'</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'b--'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="s1">'b--'</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$x$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"b"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$y$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"b"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$r$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$\alpha$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.75</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> + +<span class="n">alpha</span> <span class="o">=</span> <span class="n">pi</span><span class="o">-</span><span class="n">theta1</span> +<span class="n">draw_angle</span><span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">offset</span><span class="o">=</span><span class="n">theta0</span><span class="o">+</span><span class="n">theta1</span><span class="p">,</span> <span class="n">origin</span><span class="o">=</span><span class="p">[</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.1</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../_images/Planar_Two_Link_IK_7_0.png" src="../../_images/Planar_Two_Link_IK_7_0.png" /> +<p>The distance from the end-effector to the robot base (shoulder joint) is +<span class="math notranslate nohighlight">\(r\)</span> and can be written in terms of the end-effector position using +the Pythagorean Theorem.</p> +<p><span class="math notranslate nohighlight">\(r^2\)</span> = <span class="math notranslate nohighlight">\(x^2 + y^2\)</span></p> +<p>Then, by the law of cosines, <span class="math notranslate nohighlight">\(r\)</span>2 can also be written as:</p> +<p><span class="math notranslate nohighlight">\(r^2\)</span> = <span class="math notranslate nohighlight">\(l_0^2 + l_1^2 - 2l_0l_1\cos(\alpha)\)</span></p> +<p>Because <span class="math notranslate nohighlight">\(\alpha\)</span> can be written as <span class="math notranslate nohighlight">\(\pi - \theta_1\)</span>, we can +relate the desired end-effector position to one of our joint angles, +<span class="math notranslate nohighlight">\(\theta_1\)</span>.</p> +<p><span class="math notranslate nohighlight">\(x^2 + y^2\)</span> = <span class="math notranslate nohighlight">\(l_0^2 + l_1^2 - 2l_0l_1\cos(\alpha)\)</span></p> +<p><span class="math notranslate nohighlight">\(x^2 + y^2\)</span> = <span class="math notranslate nohighlight">\(l_0^2 + l_1^2 - 2l_0l_1\cos(\pi-\theta_1)\)</span></p> +<p><span class="math notranslate nohighlight">\(2l_0l_1\cos(\pi-\theta_1) = l_0^2 + l_1^2 - x^2 - y^2\)</span></p> +<div class="line-block"> +<div class="line"><span class="math notranslate nohighlight">\(\cos(\pi-\theta_1) = \frac{l_0^2 + l_1^2 - x^2 - y^2}{2l_0l_1}\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(~\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(~\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(\cos(\pi-\theta_1) = -cos(\theta_1)\)</span> is a trigonometric +identity, so we can also write</div> +</div> +<p><span class="math notranslate nohighlight">\(\cos(\theta_1) = \frac{x^2 + y^2 - l_0^2 - l_1^2}{2l_0l_1}\)</span></p> +<p>which leads us to an equation for <span class="math notranslate nohighlight">\(\theta_1\)</span> in terms of the link +lengths and the desired end-effector position!</p> +<p><span class="math notranslate nohighlight">\(\theta_1 = \cos^{-1}(\frac{x^2 + y^2 - l_0^2 - l_1^2}{2l_0l_1})\)</span></p> +<p>This is actually one of two possible solutions for <span class="math notranslate nohighlight">\(\theta_1\)</span>, but +we’ll ignore the other possibility for now. This solution will lead us +to the “arm-down” configuration of the arm, which is what’s shown in the +diagram. Now we’ll derive an equation for <span class="math notranslate nohighlight">\(\theta_0\)</span> that depends +on this value of <span class="math notranslate nohighlight">\(\theta_1\)</span>.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">atan2</span> + +<span class="n">arm</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'k--'</span><span class="p">)</span> + +<span class="n">p</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">cos</span><span class="p">(</span><span class="n">theta1</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">p</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">theta0</span><span class="p">)],</span> + <span class="p">[</span><span class="n">arm</span><span class="o">.</span><span class="n">elbow</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">p</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">theta0</span><span class="p">)],</span> + <span class="s1">'b--'</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">p</span><span class="o">*</span><span class="n">cos</span><span class="p">(</span><span class="n">theta0</span><span class="p">)],</span> + <span class="p">[</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">p</span><span class="o">*</span><span class="n">sin</span><span class="p">(</span><span class="n">theta0</span><span class="p">)],</span> + <span class="s1">'b--'</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> + +<span class="n">beta</span> <span class="o">=</span> <span class="n">atan2</span><span class="p">(</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="o">-</span><span class="n">theta0</span> +<span class="n">draw_angle</span><span class="p">(</span><span class="n">beta</span><span class="p">,</span> <span class="n">offset</span><span class="o">=</span><span class="n">theta0</span><span class="p">,</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.45</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$\beta$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.35</span><span class="p">,</span> <span class="mf">0.35</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$r$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$l_1sin(\theta_1)$"</span><span class="p">,</span><span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">1.25</span><span class="p">,</span> <span class="mf">1.1</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"b"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$l_1cos(\theta_1)$"</span><span class="p">,</span><span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">1.1</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"b"</span><span class="p">)</span> + +<span class="n">label_diagram</span><span class="p">()</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../_images/Planar_Two_Link_IK_9_0.png" src="../../_images/Planar_Two_Link_IK_9_0.png" /> +<p>Consider the angle between the displacement vector <span class="math notranslate nohighlight">\(r\)</span> and the +first link <span class="math notranslate nohighlight">\(l_0\)</span>; let’s call it <span class="math notranslate nohighlight">\(\beta\)</span>. If we extend the +first link to include the component of the second link in the same +direction as the first, we form a right triangle with components +<span class="math notranslate nohighlight">\(l_0+l_1cos(\theta_1)\)</span> and <span class="math notranslate nohighlight">\(l_1sin(\theta_1)\)</span>, allowing us +to express <span class="math notranslate nohighlight">\(\beta\)</span> as</p> +<p><span class="math notranslate nohighlight">\(\beta = \tan^{-1}(\frac{l_1\sin(\theta_1)}{l_0+l_1\cos(\theta_1)})\)</span></p> +<p>We now have an expression for this angle <span class="math notranslate nohighlight">\(\beta\)</span> in terms of one +of our arm’s joint angles. Now, can we relate <span class="math notranslate nohighlight">\(\beta\)</span> to +<span class="math notranslate nohighlight">\(\theta_0\)</span>? Yes!</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">arm</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span> +<span class="n">label_diagram</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'k--'</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> + <span class="s1">'b--'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="s1">'b--'</span><span class="p">)</span> + +<span class="n">gamma</span> <span class="o">=</span> <span class="n">atan2</span><span class="p">(</span><span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">arm</span><span class="o">.</span><span class="n">wrist</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> +<span class="n">draw_angle</span><span class="p">(</span><span class="n">beta</span><span class="p">,</span> <span class="n">offset</span><span class="o">=</span><span class="n">theta0</span><span class="p">,</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span> +<span class="n">draw_angle</span><span class="p">(</span><span class="n">gamma</span><span class="p">,</span> <span class="n">r</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$x$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.7</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"b"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"$y$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"b"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$\beta$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">r</span><span class="s2">"$\gamma$"</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">),</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../_images/Planar_Two_Link_IK_12_0.png" src="../../_images/Planar_Two_Link_IK_12_0.png" /> +<p>Our first joint angle <span class="math notranslate nohighlight">\(\theta_0\)</span> added to <span class="math notranslate nohighlight">\(\beta\)</span> gives us +the angle between the positive <span class="math notranslate nohighlight">\(x\)</span>-axis and the displacement +vector <span class="math notranslate nohighlight">\(r\)</span>; let’s call this angle <span class="math notranslate nohighlight">\(\gamma\)</span>.</p> +<p><span class="math notranslate nohighlight">\(\gamma = \theta_0+\beta\)</span></p> +<p><span class="math notranslate nohighlight">\(\theta_0\)</span>, our remaining joint angle, can then be expressed as</p> +<p><span class="math notranslate nohighlight">\(\theta_0 = \gamma-\beta\)</span></p> +<p>We already know <span class="math notranslate nohighlight">\(\beta\)</span>. <span class="math notranslate nohighlight">\(\gamma\)</span> is simply the inverse +tangent of <span class="math notranslate nohighlight">\(\frac{y}{x}\)</span>, so we have an equation of +<span class="math notranslate nohighlight">\(\theta_0\)</span>!</p> +<p><span class="math notranslate nohighlight">\(\theta_0 = \tan^{-1}(\frac{y}{x})-\tan^{-1}(\frac{l_1\sin(\theta_1)}{l_0+l_1\cos(\theta_1)})\)</span></p> +<p>We now have the inverse kinematics for a planar two-link robotic arm. If +you’re planning on implementing this in a programming language, it’s +best to use the atan2 function, which is included in most math libraries +and correctly accounts for the signs of <span class="math notranslate nohighlight">\(y\)</span> and <span class="math notranslate nohighlight">\(x\)</span>. Notice +that <span class="math notranslate nohighlight">\(\theta_1\)</span> must be calculated before <span class="math notranslate nohighlight">\(\theta_0\)</span>.</p> +<div class="line-block"> +<div class="line"><span class="math notranslate nohighlight">\(\theta_1 = \cos^{-1}(\frac{x^2 + y^2 - l_0^2 - l_1^2}{2l_0l_1})\)</span></div> +<div class="line"><span class="math notranslate nohighlight">\(\theta_0 = atan2(y, x)-atan2(l_1\sin(\theta_1), l_0+l_1\cos(\theta_1))\)</span></div> +</div> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="arm_navigation.html" class="btn btn-neutral float-left" title="Arm Navigation" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="n_joint_arm_to_point_control.html" class="btn btn-neutral float-right" title="N joint arm to point control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/bipedal/bipedal.html b/modules/bipedal/bipedal.html new file mode 100644 index 00000000000..361d38aa40c --- /dev/null +++ b/modules/bipedal/bipedal.html @@ -0,0 +1,150 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Bipedal — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Bipedal Planner" href="bipedal_planner/bipedal_planner.html" /> + <link rel="prev" title="Rocket powered landing" href="../aerial_navigation/rocket_powered_landing/rocket_powered_landing.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Bipedal</a><ul> +<li class="toctree-l2"><a class="reference internal" href="bipedal_planner/bipedal_planner.html">Bipedal Planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Bipedal</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/bipedal/bipedal_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="bipedal"> +<span id="id1"></span><h1>Bipedal<a class="headerlink" href="#bipedal" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="bipedal_planner/bipedal_planner.html">Bipedal Planner</a></li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../aerial_navigation/rocket_powered_landing/rocket_powered_landing.html" class="btn btn-neutral float-left" title="Rocket powered landing" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="bipedal_planner/bipedal_planner.html" class="btn btn-neutral float-right" title="Bipedal Planner" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/bipedal/bipedal_planner/bipedal_planner.html b/modules/bipedal/bipedal_planner/bipedal_planner.html new file mode 100644 index 00000000000..a2dd022b658 --- /dev/null +++ b/modules/bipedal/bipedal_planner/bipedal_planner.html @@ -0,0 +1,147 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Bipedal Planner — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Control" href="../../control/control.html" /> + <link rel="prev" title="Bipedal" href="../bipedal.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../bipedal.html">Bipedal</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Bipedal Planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../bipedal.html">Bipedal</a> »</li> + <li>Bipedal Planner</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/bipedal/bipedal_planner/bipedal_planner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="bipedal-planner"> +<h1>Bipedal Planner<a class="headerlink" href="#bipedal-planner" title="Permalink to this headline"></a></h1> +<p>Bipedal Walking with modifying designated footsteps</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Bipedal/bipedal_planner/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Bipedal/bipedal_planner/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../bipedal.html" class="btn btn-neutral float-left" title="Bipedal" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../control/control.html" class="btn btn-neutral float-right" title="Control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/control/control.html b/modules/control/control.html new file mode 100644 index 00000000000..85cb8a1ad66 --- /dev/null +++ b/modules/control/control.html @@ -0,0 +1,164 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Inverted Pendulum Control" href="inverted_pendulum_control/inverted_pendulum_control.html" /> + <link rel="prev" title="Bipedal Planner" href="../bipedal/bipedal_planner/bipedal_planner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="inverted_pendulum_control/inverted_pendulum_control.html">Inverted Pendulum Control</a></li> +<li class="toctree-l2"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html">Move to a Pose Control</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/control/control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="control"> +<span id="id1"></span><h1>Control<a class="headerlink" href="#control" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="inverted_pendulum_control/inverted_pendulum_control.html">Inverted Pendulum Control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="inverted_pendulum_control/inverted_pendulum_control.html#modeling">Modeling</a></li> +<li class="toctree-l2"><a class="reference internal" href="inverted_pendulum_control/inverted_pendulum_control.html#lqr-control">LQR control</a></li> +<li class="toctree-l2"><a class="reference internal" href="inverted_pendulum_control/inverted_pendulum_control.html#mpc-control">MPC control</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html">Move to a Pose Control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html#position-control-of-non-holonomic-systems">Position Control of non-Holonomic Systems</a></li> +<li class="toctree-l2"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html#pathfindercontroller-class">PathFinderController class</a></li> +<li class="toctree-l2"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html#how-does-the-algorithm-work">How does the Algorithm Work</a></li> +<li class="toctree-l2"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html#move-to-a-pose-robot-class">Move to a Pose Robot (Class)</a></li> +<li class="toctree-l2"><a class="reference internal" href="move_to_a_pose_control/move_to_a_pose_control.html#references">References</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../bipedal/bipedal_planner/bipedal_planner.html" class="btn btn-neutral float-left" title="Bipedal Planner" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="inverted_pendulum_control/inverted_pendulum_control.html" class="btn btn-neutral float-right" title="Inverted Pendulum Control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/control/inverted_pendulum_control/inverted_pendulum_control.html b/modules/control/inverted_pendulum_control/inverted_pendulum_control.html new file mode 100644 index 00000000000..3ad51024b7c --- /dev/null +++ b/modules/control/inverted_pendulum_control/inverted_pendulum_control.html @@ -0,0 +1,226 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Inverted Pendulum Control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Move to a Pose Control" href="../move_to_a_pose_control/move_to_a_pose_control.html" /> + <link rel="prev" title="Control" href="../control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../control.html">Control</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Inverted Pendulum Control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#modeling">Modeling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lqr-control">LQR control</a></li> +<li class="toctree-l3"><a class="reference internal" href="#mpc-control">MPC control</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../move_to_a_pose_control/move_to_a_pose_control.html">Move to a Pose Control</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../control.html">Control</a> »</li> + <li>Inverted Pendulum Control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/control/inverted_pendulum_control/inverted_pendulum_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="inverted-pendulum-control"> +<h1>Inverted Pendulum Control<a class="headerlink" href="#inverted-pendulum-control" title="Permalink to this headline"></a></h1> +<p>An inverted pendulum on a cart consists of a mass <span class="math notranslate nohighlight">\(m\)</span> at the top of a pole of length <span class="math notranslate nohighlight">\(l\)</span> pivoted on a +horizontally moving base as shown in the adjacent.</p> +<p>The objective of the control system is to balance the inverted pendulum by applying a force to the cart that the pendulum is attached to.</p> +<section id="modeling"> +<h2>Modeling<a class="headerlink" href="#modeling" title="Permalink to this headline"></a></h2> +<img alt="../../../_images/inverted-pendulum.png" class="align-center" src="../../../_images/inverted-pendulum.png" /> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(M\)</span>: mass of the cart</p></li> +<li><p><span class="math notranslate nohighlight">\(m\)</span>: mass of the load on the top of the rod</p></li> +<li><p><span class="math notranslate nohighlight">\(l\)</span>: length of the rod</p></li> +<li><p><span class="math notranslate nohighlight">\(u\)</span>: force applied to the cart</p></li> +<li><p><span class="math notranslate nohighlight">\(x\)</span>: cart position coordinate</p></li> +<li><p><span class="math notranslate nohighlight">\(\theta\)</span>: pendulum angle from vertical</p></li> +</ul> +<p>Using Lagrange’s equations:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& (M + m)\ddot{x} - ml\ddot{\theta}cos{\theta} + ml\dot{\theta^2}\sin{\theta} = u \\ +& l\ddot{\theta} - g\sin{\theta} = \ddot{x}\cos{\theta}\end{split}\]</div> +<p>See this <a class="reference external" href="https://en.wikipedia.org/wiki/Inverted_pendulum#From_Lagrange's_equations">link</a> for more details.</p> +<p>So</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& \ddot{x} = \frac{m(gcos{\theta} - \dot{\theta}^2l)sin{\theta} + u}{M + m - mcos^2{\theta}} \\ +& \ddot{\theta} = \frac{g(M + m)sin{\theta} - \dot{\theta}^2lmsin{\theta}cos{\theta} + ucos{\theta}}{l(M + m - mcos^2{\theta})}\end{split}\]</div> +<p>Linearized model when <span class="math notranslate nohighlight">\(\theta\)</span> small, <span class="math notranslate nohighlight">\(cos{\theta} \approx 1\)</span>, <span class="math notranslate nohighlight">\(sin{\theta} \approx \theta\)</span>, <span class="math notranslate nohighlight">\(\dot{\theta}^2 \approx 0\)</span>.</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& \ddot{x} = \frac{gm}{M}\theta + \frac{1}{M}u\\ +& \ddot{\theta} = \frac{g(M + m)}{Ml}\theta + \frac{1}{Ml}u\end{split}\]</div> +<p>State space:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& \dot{x} = Ax + Bu \\ +& y = Cx + Du\end{split}\]</div> +<p>where</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& x = [x, \dot{x}, \theta,\dot{\theta}]\\ +& A = \begin{bmatrix} 0 & 1 & 0 & 0\\0 & 0 & \frac{gm}{M} & 0\\0 & 0 & 0 & 1\\0 & 0 & \frac{g(M + m)}{Ml} & 0 \end{bmatrix}\\ +& B = \begin{bmatrix} 0 \\ \frac{1}{M} \\ 0 \\ \frac{1}{Ml} \end{bmatrix}\end{split}\]</div> +<p>If control only theta</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& C = \begin{bmatrix} 0 & 0 & 1 & 0 \end{bmatrix}\\ +& D = [0]\end{split}\]</div> +<p>If control x and theta</p> +<div class="math notranslate nohighlight"> +\[\begin{split}& C = \begin{bmatrix} 1 & 0 & 0 & 0\\0 & 0 & 1 & 0 \end{bmatrix}\\ +& D = \begin{bmatrix} 0 \\ 0 \end{bmatrix}\end{split}\]</div> +</section> +<section id="lqr-control"> +<h2>LQR control<a class="headerlink" href="#lqr-control" title="Permalink to this headline"></a></h2> +<p>The LQR controller minimize this cost function defined as:</p> +<div class="math notranslate nohighlight"> +\[J = x^T Q x + u^T R u\]</div> +<p>the feedback control law that minimizes the value of the cost is:</p> +<div class="math notranslate nohighlight"> +\[u = -K x\]</div> +<p>where:</p> +<div class="math notranslate nohighlight"> +\[K = (B^T P B + R)^{-1} B^T P A\]</div> +<p>and <span class="math notranslate nohighlight">\(P\)</span> is the unique positive definite solution to the discrete time +<a class="reference external" href="https://en.wikipedia.org/wiki/Inverted_pendulum#From_Lagrange's_equations">algebraic Riccati equation</a> (DARE):</p> +<div class="math notranslate nohighlight"> +\[P = A^T P A - A^T P B ( R + B^T P B )^{-1} B^T P A + Q\]</div> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Control/InvertedPendulumCart/animation_lqr.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Control/InvertedPendulumCart/animation_lqr.gif" /> +</section> +<section id="mpc-control"> +<h2>MPC control<a class="headerlink" href="#mpc-control" title="Permalink to this headline"></a></h2> +<p>The MPC controller minimize this cost function defined as:</p> +<div class="math notranslate nohighlight"> +\[J = x^T Q x + u^T R u\]</div> +<p>subject to:</p> +<ul class="simple"> +<li><p>Linearized Inverted Pendulum model</p></li> +<li><p>Initial state</p></li> +</ul> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Control/InvertedPendulumCart/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Control/InvertedPendulumCart/animation.gif" /> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../control.html" class="btn btn-neutral float-left" title="Control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../move_to_a_pose_control/move_to_a_pose_control.html" class="btn btn-neutral float-right" title="Move to a Pose Control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/control/move_to_a_pose_control/move_to_a_pose_control.html b/modules/control/move_to_a_pose_control/move_to_a_pose_control.html new file mode 100644 index 00000000000..b23d7da1e4e --- /dev/null +++ b/modules/control/move_to_a_pose_control/move_to_a_pose_control.html @@ -0,0 +1,338 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Move to a Pose Control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Utilities" href="../../utils/utils.html" /> + <link rel="prev" title="Inverted Pendulum Control" href="../inverted_pendulum_control/inverted_pendulum_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../control.html">Control</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../inverted_pendulum_control/inverted_pendulum_control.html">Inverted Pendulum Control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Move to a Pose Control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#position-control-of-non-holonomic-systems">Position Control of non-Holonomic Systems</a></li> +<li class="toctree-l3"><a class="reference internal" href="#pathfindercontroller-class">PathFinderController class</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#constructor">Constructor</a></li> +<li class="toctree-l4"><a class="reference internal" href="#member-function-s">Member function(s)</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#how-does-the-algorithm-work">How does the Algorithm Work</a></li> +<li class="toctree-l3"><a class="reference internal" href="#move-to-a-pose-robot-class">Move to a Pose Robot (Class)</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#robot-class">Robot Class</a></li> +<li class="toctree-l4"><a class="reference internal" href="#id1">Constructor</a></li> +<li class="toctree-l4"><a class="reference internal" href="#id2">Member function(s)</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../control.html">Control</a> »</li> + <li>Move to a Pose Control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/control/move_to_a_pose_control/move_to_a_pose_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="move-to-a-pose-control"> +<h1>Move to a Pose Control<a class="headerlink" href="#move-to-a-pose-control" title="Permalink to this headline"></a></h1> +<p>In this section, we present the logic of PathFinderController that drives a car from a start pose (x, y, theta) to a goal pose. A simulation of moving to a pose control is presented below.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/move_to_pose/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/move_to_pose/animation.gif" /> +<section id="position-control-of-non-holonomic-systems"> +<h2>Position Control of non-Holonomic Systems<a class="headerlink" href="#position-control-of-non-holonomic-systems" title="Permalink to this headline"></a></h2> +<p>This section explains the logic of a position controller for systems with constraint (non-Holonomic system).</p> +<p>The position control of a 1-DOF (Degree of Freedom) system is quite straightforward. We only need to compute a position error and multiply it with a proportional gain to create a command. The actuator of the system takes this command and drive the system to the target position. This controller can be easily extended to higher dimensions (e.g., using Kp_x and Kp_y gains for a 2D position control). In these systems, the number of control commands is equal to the number of degrees of freedom (Holonomic system).</p> +<p>To describe the configuration of a car on a 2D plane, we need three DOFs (i.e., x, y, and theta). But to drive a car we only need two control commands (theta_engine and theta_steering_wheel). This difference is because of a constraint between the x and y DOFs. The relationship between the delta_x and delta_y is governed by the theta_steering_wheel.</p> +<p>Note that a car is normally a non-Holonomic system but if the road is slippery, the car turns into a Holonomic system and thus it needs three independent commands to be controlled.</p> +</section> +<section id="pathfindercontroller-class"> +<h2>PathFinderController class<a class="headerlink" href="#pathfindercontroller-class" title="Permalink to this headline"></a></h2> +<section id="constructor"> +<h3>Constructor<a class="headerlink" href="#constructor" title="Permalink to this headline"></a></h3> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">PathFinderController</span><span class="p">(</span><span class="n">Kp_rho</span><span class="p">,</span> <span class="n">Kp_alpha</span><span class="p">,</span> <span class="n">Kp_beta</span><span class="p">)</span> +</pre></div> +</div> +<p>Constructs an instantiate of the PathFinderController for navigating a 3-DOF wheeled robot on a 2D plane.</p> +<p>Parameters:</p> +<ul> +<li><div class="line-block"> +<div class="line"><strong>Kp_rho</strong> : The linear velocity gain to translate the robot along a line towards the goal</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>Kp_alpha</strong> : The angular velocity gain to rotate the robot towards the goal</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>Kp_beta</strong> : The offset angular velocity gain accounting for smooth merging to the goal angle (i.e., it helps the robot heading to be parallel to the target angle.)</div> +</div> +</li> +</ul> +</section> +<section id="member-function-s"> +<h3>Member function(s)<a class="headerlink" href="#member-function-s" title="Permalink to this headline"></a></h3> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">calc_control_command</span><span class="p">(</span><span class="n">x_diff</span><span class="p">,</span> <span class="n">y_diff</span><span class="p">,</span> <span class="n">theta</span><span class="p">,</span> <span class="n">theta_goal</span><span class="p">)</span> +</pre></div> +</div> +<p>Returns the control command for the linear and angular velocities as well as the distance to goal</p> +<p>Parameters:</p> +<ul> +<li><div class="line-block"> +<div class="line"><strong>x_diff</strong> : The position of target with respect to current robot position in x direction</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>y_diff</strong> : The position of target with respect to current robot position in y direction</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>theta</strong> : The current heading angle of robot with respect to x axis</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>theta_goal</strong> : The target angle of robot with respect to x axis</div> +</div> +</li> +</ul> +<p>Returns:</p> +<ul> +<li><div class="line-block"> +<div class="line"><strong>rho</strong> : The distance between the robot and the goal position</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>v</strong> : Command linear velocity</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>w</strong> : Command angular velocity</div> +</div> +</li> +</ul> +</section> +</section> +<section id="how-does-the-algorithm-work"> +<h2>How does the Algorithm Work<a class="headerlink" href="#how-does-the-algorithm-work" title="Permalink to this headline"></a></h2> +<p>The distance between the robot and the goal position, <span class="math notranslate nohighlight">\(\rho\)</span>, is computed as</p> +<div class="math notranslate nohighlight"> +\[\rho = \sqrt{(x_{robot} - x_{target})^2 + (y_{robot} - y_{target})^2}.\]</div> +<p>The distance <span class="math notranslate nohighlight">\(\rho\)</span> is used to determine the robot speed. The idea is to slow down the robot as it gets closer to the target.</p> +<div class="math notranslate nohighlight" id="equation-move-to-a-pose-eq1"> +<span class="eqno">(1)<a class="headerlink" href="#equation-move-to-a-pose-eq1" title="Permalink to this equation"></a></span>\[v = K_P{_\rho} \times \rho\qquad\]</div> +<p>Note that for your applications, you need to tune the speed gain, <span class="math notranslate nohighlight">\(K_P{_\rho}\)</span> to a proper value.</p> +<p>To turn the robot and align its heading, <span class="math notranslate nohighlight">\(\theta\)</span>, toward the target position (not orientation), <span class="math notranslate nohighlight">\(\rho \vec{u}\)</span>, we need to compute the angle difference <span class="math notranslate nohighlight">\(\alpha\)</span>.</p> +<div class="math notranslate nohighlight"> +\[\alpha = (\arctan2(y_{diff}, x_{diff}) - \theta + \pi) mod (2\pi) - \pi\]</div> +<p>The term <span class="math notranslate nohighlight">\(mod(2\pi)\)</span> is used to map the angle to <span class="math notranslate nohighlight">\([-\pi, \pi)\)</span> range.</p> +<p>Lastly to correct the orientation of the robot, we need to compute the orientation error, <span class="math notranslate nohighlight">\(\beta\)</span>, of the robot.</p> +<div class="math notranslate nohighlight"> +\[\beta = (\theta_{goal} - \theta - \alpha + \pi) mod (2\pi) - \pi\]</div> +<p>Note that to cancel out the effect of <span class="math notranslate nohighlight">\(\alpha\)</span> when the robot is at the vicinity of the target, the term</p> +<p><span class="math notranslate nohighlight">\(-\alpha\)</span> is included.</p> +<p>The final angular speed command is given by</p> +<div class="math notranslate nohighlight" id="equation-move-to-a-pose-eq2"> +<span class="eqno">(2)<a class="headerlink" href="#equation-move-to-a-pose-eq2" title="Permalink to this equation"></a></span>\[\omega = K_P{_\alpha} \alpha - K_P{_\beta} \beta\qquad\]</div> +<p>The linear and angular speeds (Equations <a class="reference internal" href="#equation-move-to-a-pose-eq1">(1)</a> and <a class="reference internal" href="#equation-move-to-a-pose-eq2">(2)</a>) are the output of the algorithm.</p> +</section> +<section id="move-to-a-pose-robot-class"> +<h2>Move to a Pose Robot (Class)<a class="headerlink" href="#move-to-a-pose-robot-class" title="Permalink to this headline"></a></h2> +<p>This program (move_to_pose_robot.py) provides a Robot class to define different robots with different specifications. +Using this class, you can simulate different robots simultaneously and compare the effect of your parameter settings.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Control/move_to_pos_robot_class/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Control/move_to_pos_robot_class/animation.gif" /> +<p>Note: The robot class is based on PathFinderController class in ‘the move_to_pose.py’.</p> +<section id="robot-class"> +<h3>Robot Class<a class="headerlink" href="#robot-class" title="Permalink to this headline"></a></h3> +</section> +<section id="id1"> +<h3>Constructor<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">Robot</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">max_linear_speed</span><span class="p">,</span> <span class="n">max_angular_speed</span><span class="p">,</span> <span class="n">path_finder_controller</span><span class="p">)</span> +</pre></div> +</div> +<p>Constructs an instantiate of the 3-DOF wheeled Robot navigating on a 2D plane</p> +<p>Parameters:</p> +<ul> +<li><div class="line-block"> +<div class="line"><strong>name</strong> : (string) The name of the robot</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>color</strong> : (string) The color of the robot</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>max_linear_speed</strong> : (float) The maximum linear speed that the robot can go</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>max_angular_speed</strong> : (float) The maximum angular speed that the robot can rotate about its vertical axis</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>path_finder_controller</strong> : (PathFinderController) A configurable controller to finds the path and calculates command linear and angular velocities.</div> +</div> +</li> +</ul> +</section> +<section id="id2"> +<h3>Member function(s)<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">set_start_target_poses</span><span class="p">(</span><span class="n">pose_start</span><span class="p">,</span> <span class="n">pose_target</span><span class="p">)</span> +</pre></div> +</div> +<p>Sets the start and target positions of the robot.</p> +<p>Parameters:</p> +<ul> +<li><div class="line-block"> +<div class="line"><strong>pose_start</strong> : (Pose) Start postion of the robot (see the Pose class)</div> +</div> +</li> +<li><div class="line-block"> +<div class="line"><strong>pose_target</strong> : (Pose) Target postion of the robot (see the Pose class)</div> +</div> +</li> +</ul> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">move</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span> +</pre></div> +</div> +<p>Move the robot for one time step increment</p> +<p>Parameters:</p> +<ul> +<li><div class="line-block"> +<div class="line"><strong>dt</strong> : <float> time increment</div> +</div> +</li> +</ul> +</section> +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p>PathFinderController class</p></li> +<li><p><a class="reference external" href="https://link.springer.com/book/10.1007/978-3-642-20144-8">P. I. Corke, “Robotics, Vision and Control” | SpringerLink +p102</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../inverted_pendulum_control/inverted_pendulum_control.html" class="btn btn-neutral float-left" title="Inverted Pendulum Control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../utils/utils.html" class="btn btn-neutral float-right" title="Utilities" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/introduction.html b/modules/introduction.html new file mode 100644 index 00000000000..802694e74ac --- /dev/null +++ b/modules/introduction.html @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Introduction — PythonRobotics documentation</title> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script> + <script src="../_static/jquery.js"></script> + <script src="../_static/underscore.js"></script> + <script src="../_static/doctools.js"></script> + <script src="../_static/clipboard.min.js"></script> + <script src="../_static/copybutton.js"></script> + <script src="../_static/dark_mode_js/default_dark.js"></script> + <script src="../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../genindex.html" /> + <link rel="search" title="Search" href="../search.html" /> + <link rel="next" title="Localization" href="localization/localization.html" /> + <link rel="prev" title="Getting Started" href="../getting_started.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../index.html" class="icon icon-home"> PythonRobotics + <img src="../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../getting_started.html">Getting Started</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Introduction</a><ul> +<li class="toctree-l2"><a class="reference internal" href="#definition-of-robotics">Definition Of Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#history-of-robotics">History Of Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#application-of-robotics">Application Of Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#software-for-robotics">Software for Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#id1">Software for Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#python-for-robotics">Python for Robotics</a></li> +<li class="toctree-l2"><a class="reference internal" href="#learning-robotics-algorithms">Learning Robotics Algorithms</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../index.html" class="icon icon-home"></a> »</li> + <li>Introduction</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/introduction_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="introduction"> +<h1>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h1> +<p>TBD</p> +<section id="definition-of-robotics"> +<h2>Definition Of Robotics<a class="headerlink" href="#definition-of-robotics" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +<section id="history-of-robotics"> +<h2>History Of Robotics<a class="headerlink" href="#history-of-robotics" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +<section id="application-of-robotics"> +<h2>Application Of Robotics<a class="headerlink" href="#application-of-robotics" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +<section id="software-for-robotics"> +<h2>Software for Robotics<a class="headerlink" href="#software-for-robotics" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +<section id="id1"> +<h2>Software for Robotics<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +<section id="python-for-robotics"> +<h2>Python for Robotics<a class="headerlink" href="#python-for-robotics" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +<section id="learning-robotics-algorithms"> +<h2>Learning Robotics Algorithms<a class="headerlink" href="#learning-robotics-algorithms" title="Permalink to this headline"></a></h2> +<p>TBD</p> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../getting_started.html" class="btn btn-neutral float-left" title="Getting Started" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="localization/localization.html" class="btn btn-neutral float-right" title="Localization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html b/modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html new file mode 100644 index 00000000000..4dd3ad27196 --- /dev/null +++ b/modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html @@ -0,0 +1,153 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Ensamble Kalman Filter Localization — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Unscented Kalman Filter localization" href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html" /> + <link rel="prev" title="Extended Kalman Filter Localization" href="../extended_kalman_filter_localization_files/extended_kalman_filter_localization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../localization.html">Localization</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../particle_filter_localization/particle_filter_localization.html">Particle filter localization</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../localization.html">Localization</a> »</li> + <li>Ensamble Kalman Filter Localization</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="ensamble-kalman-filter-localization"> +<h1>Ensamble Kalman Filter Localization<a class="headerlink" href="#ensamble-kalman-filter-localization" title="Permalink to this headline"></a></h1> +<figure class="align-default"> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/ensamble_kalman_filter/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/ensamble_kalman_filter/animation.gif" /> +</figure> +<p>This is a sensor fusion localization with Ensamble Kalman Filter(EnKF).</p> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../extended_kalman_filter_localization_files/extended_kalman_filter_localization.html" class="btn btn-neutral float-left" title="Extended Kalman Filter Localization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html" class="btn btn-neutral float-right" title="Unscented Kalman Filter localization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization.html b/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization.html new file mode 100644 index 00000000000..3713fd728b9 --- /dev/null +++ b/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization.html @@ -0,0 +1,253 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Extended Kalman Filter Localization — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Ensamble Kalman Filter Localization" href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html" /> + <link rel="prev" title="Localization" href="../localization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../localization.html">Localization</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Extended Kalman Filter Localization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#filter-design">Filter design</a></li> +<li class="toctree-l3"><a class="reference internal" href="#motion-model">Motion Model</a></li> +<li class="toctree-l3"><a class="reference internal" href="#observation-model">Observation Model</a></li> +<li class="toctree-l3"><a class="reference internal" href="#extended-kalman-filter">Extended Kalman Filter</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ref">Ref:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../particle_filter_localization/particle_filter_localization.html">Particle filter localization</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../localization.html">Localization</a> »</li> + <li>Extended Kalman Filter Localization</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="extended-kalman-filter-localization"> +<h1>Extended Kalman Filter Localization<a class="headerlink" href="#extended-kalman-filter-localization" title="Permalink to this headline"></a></h1> +<a class="reference internal image-reference" href="../../../_images/extended_kalman_filter_localization_1_0.png"><img alt="../../../_images/extended_kalman_filter_localization_1_0.png" src="../../../_images/extended_kalman_filter_localization_1_0.png" style="width: 600px;" /></a> +<figure class="align-default"> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/extended_kalman_filter/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/extended_kalman_filter/animation.gif" /> +</figure> +<p>This is a sensor fusion localization with Extended Kalman Filter(EKF).</p> +<p>The blue line is true trajectory, the black line is dead reckoning +trajectory,</p> +<p>the green point is positioning observation (ex. GPS), and the red line +is estimated trajectory with EKF.</p> +<p>The red ellipse is estimated covariance ellipse with EKF.</p> +<p>Code: <a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/Localization/extended_kalman_filter/extended_kalman_filter.py">PythonRobotics/extended_kalman_filter.py at master · +AtsushiSakai/PythonRobotics</a></p> +<section id="filter-design"> +<h2>Filter design<a class="headerlink" href="#filter-design" title="Permalink to this headline"></a></h2> +<p>In this simulation, the robot has a state vector includes 4 states at +time <span class="math notranslate nohighlight">\(t\)</span>.</p> +<div class="math notranslate nohighlight"> +\[\textbf{x}_t=[x_t, y_t, \phi_t, v_t]\]</div> +<p>x, y are a 2D x-y position, <span class="math notranslate nohighlight">\(\phi\)</span> is orientation, and v is +velocity.</p> +<p>In the code, “xEst” means the state vector. +<a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/916b4382de090de29f54538b356cef1c811aacce/Localization/extended_kalman_filter/extended_kalman_filter.py#L168">code</a></p> +<p>And, <span class="math notranslate nohighlight">\(P_t\)</span> is covariace matrix of the state,</p> +<p><span class="math notranslate nohighlight">\(Q\)</span> is covariance matrix of process noise,</p> +<p><span class="math notranslate nohighlight">\(R\)</span> is covariance matrix of observation noise at time <span class="math notranslate nohighlight">\(t\)</span></p> +<p>The robot has a speed sensor and a gyro sensor.</p> +<p>So, the input vecor can be used as each time step</p> +<div class="math notranslate nohighlight"> +\[\textbf{u}_t=[v_t, \omega_t]\]</div> +<p>Also, the robot has a GNSS sensor, it means that the robot can observe +x-y position at each time.</p> +<div class="math notranslate nohighlight"> +\[\textbf{z}_t=[x_t,y_t]\]</div> +<p>The input and observation vector includes sensor noise.</p> +<p>In the code, “observation” function generates the input and observation +vector with noise +<a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/916b4382de090de29f54538b356cef1c811aacce/Localization/extended_kalman_filter/extended_kalman_filter.py#L34-L50">code</a></p> +</section> +<section id="motion-model"> +<h2>Motion Model<a class="headerlink" href="#motion-model" title="Permalink to this headline"></a></h2> +<p>The robot model is</p> +<div class="math notranslate nohighlight"> +\[\dot{x} = v \cos(\phi)\]</div> +<div class="math notranslate nohighlight"> +\[\dot{y} = v \sin(\phi)\]</div> +<div class="math notranslate nohighlight"> +\[\dot{\phi} = \omega\]</div> +<p>So, the motion model is</p> +<div class="math notranslate nohighlight"> +\[\textbf{x}_{t+1} = f(\textbf{x}_t, \textbf{u}_t) = F\textbf{x}_t+B\textbf{u}_t\]</div> +<p>where</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} F= \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 \\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} B= \begin{bmatrix} cos(\phi) \Delta t & 0\\ sin(\phi) \Delta t & 0\\ 0 & \Delta t\\ 1 & 0\\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\Delta t\)</span> is a time interval.</p> +<p>This is implemented at +<a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/916b4382de090de29f54538b356cef1c811aacce/Localization/extended_kalman_filter/extended_kalman_filter.py#L53-L67">code</a></p> +<p>The motion function is that</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} \begin{bmatrix} x' \\ y' \\ w' \\ v' \end{bmatrix} = f(\textbf{x}, \textbf{u}) = \begin{bmatrix} x + v\cos(\phi)\Delta t \\ y + v\sin(\phi)\Delta t \\ \phi + \omega \Delta t \\ v \end{bmatrix} \end{equation*}\)</span></p> +<p>Its Jacobian matrix is</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} J_f = \begin{bmatrix} \frac{\partial x'}{\partial x}& \frac{\partial x'}{\partial y} & \frac{\partial x'}{\partial \phi} & \frac{\partial x'}{\partial v}\\ \frac{\partial y'}{\partial x}& \frac{\partial y'}{\partial y} & \frac{\partial y'}{\partial \phi} & \frac{\partial y'}{\partial v}\\ \frac{\partial \phi'}{\partial x}& \frac{\partial \phi'}{\partial y} & \frac{\partial \phi'}{\partial \phi} & \frac{\partial \phi'}{\partial v}\\ \frac{\partial v'}{\partial x}& \frac{\partial v'}{\partial y} & \frac{\partial v'}{\partial \phi} & \frac{\partial v'}{\partial v} \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} = \begin{bmatrix} 1& 0 & -v \sin(\phi) \Delta t & \cos(\phi) \Delta t\\ 0 & 1 & v \cos(\phi) \Delta t & \sin(\phi) \Delta t\\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \end{equation*}\)</span></p> +</section> +<section id="observation-model"> +<h2>Observation Model<a class="headerlink" href="#observation-model" title="Permalink to this headline"></a></h2> +<p>The robot can get x-y position infomation from GPS.</p> +<p>So GPS Observation model is</p> +<div class="math notranslate nohighlight"> +\[\textbf{z}_{t} = g(\textbf{x}_t) = H \textbf{x}_t\]</div> +<p>where</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} H = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ \end{bmatrix} \end{equation*}\)</span></p> +<p>The observation function states that</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} \begin{bmatrix} x' \\ y' \end{bmatrix} = g(\textbf{x}) = \begin{bmatrix} x \\ y \end{bmatrix} \end{equation*}\)</span></p> +<p>Its Jacobian matrix is</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} J_g = \begin{bmatrix} \frac{\partial x'}{\partial x} & \frac{\partial x'}{\partial y} & \frac{\partial x'}{\partial \phi} & \frac{\partial x'}{\partial v}\\ \frac{\partial y'}{\partial x}& \frac{\partial y'}{\partial y} & \frac{\partial y'}{\partial \phi} & \frac{\partial y'}{ \partial v}\\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} = \begin{bmatrix} 1& 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ \end{bmatrix} \end{equation*}\)</span></p> +</section> +<section id="extended-kalman-filter"> +<h2>Extended Kalman Filter<a class="headerlink" href="#extended-kalman-filter" title="Permalink to this headline"></a></h2> +<p>Localization process using Extended Kalman Filter:EKF is</p> +<p>=== Predict ===</p> +<p><span class="math notranslate nohighlight">\(x_{Pred} = Fx_t+Bu_t\)</span></p> +<p><span class="math notranslate nohighlight">\(P_{Pred} = J_f P_t J_f^T + Q\)</span></p> +<p>=== Update ===</p> +<p><span class="math notranslate nohighlight">\(z_{Pred} = Hx_{Pred}\)</span></p> +<p><span class="math notranslate nohighlight">\(y = z - z_{Pred}\)</span></p> +<p><span class="math notranslate nohighlight">\(S = J_g P_{Pred}.J_g^T + R\)</span></p> +<p><span class="math notranslate nohighlight">\(K = P_{Pred}.J_g^T S^{-1}\)</span></p> +<p><span class="math notranslate nohighlight">\(x_{t+1} = x_{Pred} + Ky\)</span></p> +<p><span class="math notranslate nohighlight">\(P_{t+1} = ( I - K J_g) P_{Pred}\)</span></p> +</section> +<section id="ref"> +<h2>Ref:<a class="headerlink" href="#ref" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.probabilistic-robotics.org/">PROBABILISTIC-ROBOTICS.ORG</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../localization.html" class="btn btn-neutral float-left" title="Localization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html" class="btn btn-neutral float-right" title="Ensamble Kalman Filter Localization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/localization/histogram_filter_localization/histogram_filter_localization.html b/modules/localization/histogram_filter_localization/histogram_filter_localization.html new file mode 100644 index 00000000000..ae19b9b6413 --- /dev/null +++ b/modules/localization/histogram_filter_localization/histogram_filter_localization.html @@ -0,0 +1,234 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Histogram filter localization — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Particle filter localization" href="../particle_filter_localization/particle_filter_localization.html" /> + <link rel="prev" title="Unscented Kalman Filter localization" href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../localization.html">Localization</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Histogram filter localization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#filtering-algorithm">Filtering algorithm</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#step1-filter-initialization">Step1: Filter initialization</a></li> +<li class="toctree-l4"><a class="reference internal" href="#step2-predict-probability-by-motion">Step2: Predict probability by motion</a></li> +<li class="toctree-l4"><a class="reference internal" href="#step3-update-probability-by-observation">Step3: Update probability by observation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#step4-estimate-position-from-probability">Step4: Estimate position from probability</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../particle_filter_localization/particle_filter_localization.html">Particle filter localization</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../localization.html">Localization</a> »</li> + <li>Histogram filter localization</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/localization/histogram_filter_localization/histogram_filter_localization_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="histogram-filter-localization"> +<h1>Histogram filter localization<a class="headerlink" href="#histogram-filter-localization" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/histogram_filter/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/histogram_filter/animation.gif" /> +<p>This is a 2D localization example with Histogram filter.</p> +<p>The red cross is true position, black points are RFID positions.</p> +<p>The blue grid shows a position probability of histogram filter.</p> +<p>In this simulation, we assume the robot’s yaw orientation and RFID’s positions are known, +but x,y positions are unknown.</p> +<p>The filter uses speed input and range observations from RFID for localization.</p> +<p>Initial position information is not needed.</p> +<section id="filtering-algorithm"> +<h2>Filtering algorithm<a class="headerlink" href="#filtering-algorithm" title="Permalink to this headline"></a></h2> +<p>Histogram filter is a discrete Bayes filter in continuous space.</p> +<p>It uses regular girds to manage probability of the robot existence.</p> +<p>If a grid has higher probability, it means that the robot is likely to be there.</p> +<p>In the simulation, we want to estimate x-y position, so we use 2D grid data.</p> +<p>There are 4 steps for the histogram filter to estimate the probability distribution.</p> +<section id="step1-filter-initialization"> +<h3>Step1: Filter initialization<a class="headerlink" href="#step1-filter-initialization" title="Permalink to this headline"></a></h3> +<p>Histogram filter does not need initial position information.</p> +<p>In that case, we can initialize each grid probability as a same value.</p> +<p>If we can use initial position information, we can set initial probabilities based on it.</p> +<p><a class="reference internal" href="../../mapping/gaussian_grid_map/gaussian_grid_map.html#gaussian-grid-map"><span class="std std-ref">Gaussian grid map</span></a> might be useful when the initial position information is provided as gaussian distribution.</p> +</section> +<section id="step2-predict-probability-by-motion"> +<h3>Step2: Predict probability by motion<a class="headerlink" href="#step2-predict-probability-by-motion" title="Permalink to this headline"></a></h3> +<p>In histogram filter, when a robot move to a next grid, +all probability information of each grid are shifted towards the movement direction.</p> +<p>This process represents the change in the probability distribution as the robot moves.</p> +<p>After the robot has moved, the probability distribution needs reflect +the estimation error due to the movement.</p> +<p>For example, the position probability is peaky with observations:</p> +<a class="reference internal image-reference" href="../../../_images/1.png"><img alt="../../../_images/1.png" src="../../../_images/1.png" style="width: 400px;" /></a> +<p>But, the probability is getting uncertain without observations:</p> +<a class="reference internal image-reference" href="../../../_images/2.png"><img alt="../../../_images/2.png" src="../../../_images/2.png" style="width: 400px;" /></a> +<p>The <a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html">gaussian filter</a> +is used in the simulation for adding noize.</p> +</section> +<section id="step3-update-probability-by-observation"> +<h3>Step3: Update probability by observation<a class="headerlink" href="#step3-update-probability-by-observation" title="Permalink to this headline"></a></h3> +<p>In this step, all probabilities are updated by observations, +this is the update step of bayesian filter.</p> +<p>The probability update formula is different by the used sensor model.</p> +<p>This simulation uses range observation model.</p> +<p>The probability of each grid is updated by this formula:</p> +<div class="math notranslate nohighlight"> +\[p_t=p_{t-1}*h(z)\]</div> +<div class="math notranslate nohighlight"> +\[h(z)=\frac{\exp \left(-(d - z)^{2} / 2\right)}{\sqrt{2 \pi}}\]</div> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(p_t\)</span> is the probability at the time <cite>t</cite>.</p></li> +<li><p><span class="math notranslate nohighlight">\(h(z)\)</span> is the observation probability with the observation <cite>z</cite>.</p></li> +<li><p><span class="math notranslate nohighlight">\(d\)</span> is the known distance from the RD-ID to the grid center.</p></li> +</ul> +<p>When the <cite>d</cite> is 3.0, the <cite>h(z)</cite> distribution is:</p> +<a class="reference internal image-reference" href="../../../_images/4.png"><img alt="../../../_images/4.png" src="../../../_images/4.png" style="width: 400px;" /></a> +<p>The observation probability distribution looks a circle when a RF-ID is observed:</p> +<a class="reference internal image-reference" href="../../../_images/3.png"><img alt="../../../_images/3.png" src="../../../_images/3.png" style="width: 400px;" /></a> +</section> +<section id="step4-estimate-position-from-probability"> +<h3>Step4: Estimate position from probability<a class="headerlink" href="#step4-estimate-position-from-probability" title="Permalink to this headline"></a></h3> +<p>In each time step, we can calculate the final robot position from the current probability distribution. +There are two ways to calculate the final positions:</p> +<ol class="arabic simple"> +<li><p>Using the maximum probability grid position.</p></li> +<li><p>Using the average of probability weighted grind position.</p></li> +</ol> +</section> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.probabilistic-robotics.org">_PROBABILISTIC ROBOTICS:</a></p></li> +<li><p><a class="reference external" href="http://driving.stanford.edu/papers/ICRA2010.pdf">Robust Vehicle Localization in Urban Environments Using Probabilistic Maps</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html" class="btn btn-neutral float-left" title="Unscented Kalman Filter localization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../particle_filter_localization/particle_filter_localization.html" class="btn btn-neutral float-right" title="Particle filter localization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/localization/localization.html b/modules/localization/localization.html new file mode 100644 index 00000000000..84790975e49 --- /dev/null +++ b/modules/localization/localization.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Localization — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Extended Kalman Filter Localization" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html" /> + <link rel="prev" title="Introduction" href="../introduction.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Localization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="particle_filter_localization/particle_filter_localization.html">Particle filter localization</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Localization</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/localization/localization_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="localization"> +<span id="id1"></span><h1>Localization<a class="headerlink" href="#localization" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html#filter-design">Filter design</a></li> +<li class="toctree-l2"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html#motion-model">Motion Model</a></li> +<li class="toctree-l2"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html#observation-model">Observation Model</a></li> +<li class="toctree-l2"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html#extended-kalman-filter">Extended Kalman Filter</a></li> +<li class="toctree-l2"><a class="reference internal" href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html#ref">Ref:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="unscented_kalman_filter_localization/unscented_kalman_filter_localization.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="histogram_filter_localization/histogram_filter_localization.html#filtering-algorithm">Filtering algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="histogram_filter_localization/histogram_filter_localization.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="particle_filter_localization/particle_filter_localization.html">Particle filter localization</a><ul> +<li class="toctree-l2"><a class="reference internal" href="particle_filter_localization/particle_filter_localization.html#how-to-calculate-covariance-matrix-from-particles">How to calculate covariance matrix from particles</a></li> +<li class="toctree-l2"><a class="reference internal" href="particle_filter_localization/particle_filter_localization.html#references">References:</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../introduction.html" class="btn btn-neutral float-left" title="Introduction" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="extended_kalman_filter_localization_files/extended_kalman_filter_localization.html" class="btn btn-neutral float-right" title="Extended Kalman Filter Localization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/localization/particle_filter_localization/particle_filter_localization.html b/modules/localization/particle_filter_localization/particle_filter_localization.html new file mode 100644 index 00000000000..2e1724e4dc1 --- /dev/null +++ b/modules/localization/particle_filter_localization/particle_filter_localization.html @@ -0,0 +1,181 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Particle filter localization — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Mapping" href="../../mapping/mapping.html" /> + <link rel="prev" title="Histogram filter localization" href="../histogram_filter_localization/histogram_filter_localization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../localization.html">Localization</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../unscented_kalman_filter_localization/unscented_kalman_filter_localization.html">Unscented Kalman Filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Particle filter localization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#how-to-calculate-covariance-matrix-from-particles">How to calculate covariance matrix from particles</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../localization.html">Localization</a> »</li> + <li>Particle filter localization</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/localization/particle_filter_localization/particle_filter_localization_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="particle-filter-localization"> +<h1>Particle filter localization<a class="headerlink" href="#particle-filter-localization" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/particle_filter/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/particle_filter/animation.gif" /> +<p>This is a sensor fusion localization with Particle Filter(PF).</p> +<p>The blue line is true trajectory, the black line is dead reckoning +trajectory,</p> +<p>and the red line is estimated trajectory with PF.</p> +<p>It is assumed that the robot can measure a distance from landmarks +(RFID).</p> +<p>This measurements are used for PF localization.</p> +<section id="how-to-calculate-covariance-matrix-from-particles"> +<h2>How to calculate covariance matrix from particles<a class="headerlink" href="#how-to-calculate-covariance-matrix-from-particles" title="Permalink to this headline"></a></h2> +<p>The covariance matrix <span class="math notranslate nohighlight">\(\Xi\)</span> from particle information is calculated by the following equation:</p> +<div class="math notranslate nohighlight"> +\[\Xi_{j,k}=\frac{1}{1-\sum^N_{i=1}(w^i)^2}\sum^N_{i=1}w^i(x^i_j-\mu_j)(x^i_k-\mu_k)\]</div> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(\Xi_{j,k}\)</span> is covariance matrix element at row <span class="math notranslate nohighlight">\(i\)</span> and column <span class="math notranslate nohighlight">\(k\)</span>.</p></li> +<li><p><span class="math notranslate nohighlight">\(w^i\)</span> is the weight of the <span class="math notranslate nohighlight">\(i\)</span> th particle.</p></li> +<li><p><span class="math notranslate nohighlight">\(x^i_j\)</span> is the <span class="math notranslate nohighlight">\(j\)</span> th state of the <span class="math notranslate nohighlight">\(i\)</span> th particle.</p></li> +<li><p><span class="math notranslate nohighlight">\(\mu_j\)</span> is the <span class="math notranslate nohighlight">\(j\)</span> th mean state of particles.</p></li> +</ul> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.probabilistic-robotics.org">_PROBABILISTIC ROBOTICS:</a></p></li> +<li><p><a class="reference external" href="https://arxiv.org/pdf/1801.07000.pdf">Improving the particle filter in high dimensions using conjugate artificial process noise</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../histogram_filter_localization/histogram_filter_localization.html" class="btn btn-neutral float-left" title="Histogram filter localization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../mapping/mapping.html" class="btn btn-neutral float-right" title="Mapping" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization.html b/modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization.html new file mode 100644 index 00000000000..cd7b04b2798 --- /dev/null +++ b/modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization.html @@ -0,0 +1,161 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Unscented Kalman Filter localization — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Histogram filter localization" href="../histogram_filter_localization/histogram_filter_localization.html" /> + <link rel="prev" title="Ensamble Kalman Filter Localization" href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../localization.html">Localization</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../extended_kalman_filter_localization_files/extended_kalman_filter_localization.html">Extended Kalman Filter Localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html">Ensamble Kalman Filter Localization</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Unscented Kalman Filter localization</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../histogram_filter_localization/histogram_filter_localization.html">Histogram filter localization</a></li> +<li class="toctree-l2"><a class="reference internal" href="../particle_filter_localization/particle_filter_localization.html">Particle filter localization</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../localization.html">Localization</a> »</li> + <li>Unscented Kalman Filter localization</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="unscented-kalman-filter-localization"> +<h1>Unscented Kalman Filter localization<a class="headerlink" href="#unscented-kalman-filter-localization" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/unscented_kalman_filter/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Localization/unscented_kalman_filter/animation.gif" /> +<p>This is a sensor fusion localization with Unscented Kalman Filter(UKF).</p> +<p>The lines and points are same meaning of the EKF simulation.</p> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.researchgate.net/publication/267963417_Discriminatively_Trained_Unscented_Kalman_Filter_for_Mobile_Robot_Localization">Discriminatively Trained Unscented Kalman Filter for Mobile Robot Localization</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization.html" class="btn btn-neutral float-left" title="Ensamble Kalman Filter Localization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../histogram_filter_localization/histogram_filter_localization.html" class="btn btn-neutral float-right" title="Histogram filter localization" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/circle_fitting/circle_fitting.html b/modules/mapping/circle_fitting/circle_fitting.html new file mode 100644 index 00000000000..b9daaf8c244 --- /dev/null +++ b/modules/mapping/circle_fitting/circle_fitting.html @@ -0,0 +1,158 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Object shape recognition using circle fitting — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Object shape recognition using rectangle fitting" href="../rectangle_fitting/rectangle_fitting.html" /> + <link rel="prev" title="k-means object clustering" href="../k_means_object_clustering/k_means_object_clustering.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Object shape recognition using circle fitting</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/circle_fitting/circle_fitting_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="object-shape-recognition-using-circle-fitting"> +<h1>Object shape recognition using circle fitting<a class="headerlink" href="#object-shape-recognition-using-circle-fitting" title="Permalink to this headline"></a></h1> +<p>This is an object shape recognition using circle fitting.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/circle_fitting/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/circle_fitting/animation.gif" /> +<p>The blue circle is the true object shape.</p> +<p>The red crosses are observations from a ranging sensor.</p> +<p>The red circle is the estimated object shape using circle fitting.</p> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../k_means_object_clustering/k_means_object_clustering.html" class="btn btn-neutral float-left" title="k-means object clustering" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../rectangle_fitting/rectangle_fitting.html" class="btn btn-neutral float-right" title="Object shape recognition using rectangle fitting" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/gaussian_grid_map/gaussian_grid_map.html b/modules/mapping/gaussian_grid_map/gaussian_grid_map.html new file mode 100644 index 00000000000..99b39f1fbf8 --- /dev/null +++ b/modules/mapping/gaussian_grid_map/gaussian_grid_map.html @@ -0,0 +1,155 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Gaussian grid map — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Normal Distance Transform (NDT) map" href="../ndt_map/ndt_map.html" /> + <link rel="prev" title="Mapping" href="../mapping.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Gaussian grid map</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/gaussian_grid_map/gaussian_grid_map_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="gaussian-grid-map"> +<span id="id1"></span><h1>Gaussian grid map<a class="headerlink" href="#gaussian-grid-map" title="Permalink to this headline"></a></h1> +<p>This is a 2D Gaussian grid mapping example.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/gaussian_grid_map/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/gaussian_grid_map/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../mapping.html" class="btn btn-neutral float-left" title="Mapping" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../ndt_map/ndt_map.html" class="btn btn-neutral float-right" title="Normal Distance Transform (NDT) map" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/k_means_object_clustering/k_means_object_clustering.html b/modules/mapping/k_means_object_clustering/k_means_object_clustering.html new file mode 100644 index 00000000000..478e7088d14 --- /dev/null +++ b/modules/mapping/k_means_object_clustering/k_means_object_clustering.html @@ -0,0 +1,155 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>k-means object clustering — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Object shape recognition using circle fitting" href="../circle_fitting/circle_fitting.html" /> + <link rel="prev" title="Point cloud Sampling" href="../point_cloud_sampling/point_cloud_sampling.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>k-means object clustering</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/k_means_object_clustering/k_means_object_clustering_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="k-means-object-clustering"> +<h1>k-means object clustering<a class="headerlink" href="#k-means-object-clustering" title="Permalink to this headline"></a></h1> +<p>This is a 2D object clustering with k-means algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/kmeans_clustering/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/kmeans_clustering/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../point_cloud_sampling/point_cloud_sampling.html" class="btn btn-neutral float-left" title="Point cloud Sampling" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../circle_fitting/circle_fitting.html" class="btn btn-neutral float-right" title="Object shape recognition using circle fitting" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html b/modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html new file mode 100644 index 00000000000..3da16e7dfcf --- /dev/null +++ b/modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html @@ -0,0 +1,310 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Lidar to grid map — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Point cloud Sampling" href="../point_cloud_sampling/point_cloud_sampling.html" /> + <link rel="prev" title="Ray casting grid map" href="../ray_casting_grid_map/ray_casting_grid_map.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Lidar to grid map</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="lidar-to-grid-map"> +<h1>Lidar to grid map<a class="headerlink" href="#lidar-to-grid-map" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/lidar_to_grid_map/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/lidar_to_grid_map/animation.gif" /> +<p>This simple tutorial shows how to read LIDAR (range) measurements from a +file and convert it to occupancy grid.</p> +<p>Occupancy grid maps (<em>Hans Moravec, A.E. Elfes: High resolution maps +from wide angle sonar, Proc. IEEE Int. Conf. Robotics Autom. (1985)</em>) +are a popular, probabilistic approach to represent the environment. The +grid is basically discrete representation of the environment, which +shows if a grid cell is occupied or not. Here the map is represented as +a <code class="docutils literal notranslate"><span class="pre">numpy</span> <span class="pre">array</span></code>, and numbers close to 1 means the cell is occupied +(<em>marked with red on the next image</em>), numbers close to 0 means they are +free (<em>marked with green</em>). The grid has the ability to represent +unknown (unobserved) areas, which are close to 0.5.</p> +<figure class="align-default"> +<img alt="../../../_images/grid_map_example.png" src="../../../_images/grid_map_example.png" /> +</figure> +<p>In order to construct the grid map from the measurement we need to +discretise the values. But, first let’s need to <code class="docutils literal notranslate"><span class="pre">import</span></code> some +necessary packages.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">math</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">cos</span><span class="p">,</span> <span class="n">sin</span><span class="p">,</span> <span class="n">radians</span><span class="p">,</span> <span class="n">pi</span> +</pre></div> +</div> +<p>The measurement file contains the distances and the corresponding angles +in a <code class="docutils literal notranslate"><span class="pre">csv</span></code> (comma separated values) format. Let’s write the +<code class="docutils literal notranslate"><span class="pre">file_read</span></code> method:</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">file_read</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Reading LIDAR laser beams (angles and corresponding distance data)</span> +<span class="sd"> """</span> + <span class="n">measures</span> <span class="o">=</span> <span class="p">[</span><span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="n">f</span><span class="p">)]</span> + <span class="n">angles</span> <span class="o">=</span> <span class="p">[]</span> + <span class="n">distances</span> <span class="o">=</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">measure</span> <span class="ow">in</span> <span class="n">measures</span><span class="p">:</span> + <span class="n">angles</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">measure</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span> + <span class="n">distances</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">measure</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> + <span class="n">angles</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">angles</span><span class="p">)</span> + <span class="n">distances</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">distances</span><span class="p">)</span> + <span class="k">return</span> <span class="n">angles</span><span class="p">,</span> <span class="n">distances</span> +</pre></div> +</div> +<p>From the distances and the angles it is easy to determine the <code class="docutils literal notranslate"><span class="pre">x</span></code> and +<code class="docutils literal notranslate"><span class="pre">y</span></code> coordinates with <code class="docutils literal notranslate"><span class="pre">sin</span></code> and <code class="docutils literal notranslate"><span class="pre">cos</span></code>. In order to display it +<code class="docutils literal notranslate"><span class="pre">matplotlib.pyplot</span></code> (<code class="docutils literal notranslate"><span class="pre">plt</span></code>) is used.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">ang</span><span class="p">,</span> <span class="n">dist</span> <span class="o">=</span> <span class="n">file_read</span><span class="p">(</span><span class="s2">"lidar01.csv"</span><span class="p">)</span> +<span class="n">ox</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">ang</span><span class="p">)</span> <span class="o">*</span> <span class="n">dist</span> +<span class="n">oy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">ang</span><span class="p">)</span> <span class="o">*</span> <span class="n">dist</span> +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span><span class="mi">10</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">oy</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="n">oy</span><span class="p">))],</span> <span class="p">[</span><span class="n">ox</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="n">oy</span><span class="p">))],</span> <span class="s2">"ro-"</span><span class="p">)</span> <span class="c1"># lines from 0,0 to the</span> +<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> +<span class="n">bottom</span><span class="p">,</span> <span class="n">top</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylim</span><span class="p">()</span> <span class="c1"># return the current ylim</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylim</span><span class="p">((</span><span class="n">top</span><span class="p">,</span> <span class="n">bottom</span><span class="p">))</span> <span class="c1"># rescale y axis, to match the grid orientation</span> +<span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/lidar_to_grid_map_tutorial_5_0.png" src="../../../_images/lidar_to_grid_map_tutorial_5_0.png" /> +<p>The <code class="docutils literal notranslate"><span class="pre">lidar_to_grid_map.py</span></code> contains handy functions which can used to +convert a 2D range measurement to a grid map. For example the +<code class="docutils literal notranslate"><span class="pre">bresenham</span></code> gives the a straight line between two points in a grid +map. Let’s see how this works.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">lidar_to_grid_map</span> <span class="k">as</span> <span class="nn">lg</span> +<span class="n">map1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">ones</span><span class="p">((</span><span class="mi">50</span><span class="p">,</span> <span class="mi">50</span><span class="p">))</span> <span class="o">*</span> <span class="mf">0.5</span> +<span class="n">line</span> <span class="o">=</span> <span class="n">lg</span><span class="o">.</span><span class="n">bresenham</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="mi">30</span><span class="p">))</span> +<span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span> + <span class="n">map1</span><span class="p">[</span><span class="n">l</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">l</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">map1</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">colorbar</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/lidar_to_grid_map_tutorial_7_0.png" src="../../../_images/lidar_to_grid_map_tutorial_7_0.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">line</span> <span class="o">=</span> <span class="n">lg</span><span class="o">.</span><span class="n">bresenham</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">30</span><span class="p">),</span> <span class="p">(</span><span class="mi">40</span><span class="p">,</span> <span class="mi">30</span><span class="p">))</span> +<span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span> + <span class="n">map1</span><span class="p">[</span><span class="n">l</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">l</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">line</span> <span class="o">=</span> <span class="n">lg</span><span class="o">.</span><span class="n">bresenham</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">30</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> +<span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span> + <span class="n">map1</span><span class="p">[</span><span class="n">l</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">l</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">map1</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">colorbar</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/lidar_to_grid_map_tutorial_8_0.png" src="../../../_images/lidar_to_grid_map_tutorial_8_0.png" /> +<p>To fill empty areas, a queue-based algorithm can be used that can be +used on an initialized occupancy map. The center point is given: the +algorithm checks for neighbour elements in each iteration, and stops +expansion on obstacles and free boundaries.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">deque</span> +<span class="k">def</span> <span class="nf">flood_fill</span><span class="p">(</span><span class="n">cpoint</span><span class="p">,</span> <span class="n">pmap</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> cpoint: starting point (x,y) of fill</span> +<span class="sd"> pmap: occupancy map generated from Bresenham ray-tracing</span> +<span class="sd"> """</span> + <span class="c1"># Fill empty areas with queue method</span> + <span class="n">sx</span><span class="p">,</span> <span class="n">sy</span> <span class="o">=</span> <span class="n">pmap</span><span class="o">.</span><span class="n">shape</span> + <span class="n">fringe</span> <span class="o">=</span> <span class="n">deque</span><span class="p">()</span> + <span class="n">fringe</span><span class="o">.</span><span class="n">appendleft</span><span class="p">(</span><span class="n">cpoint</span><span class="p">)</span> + <span class="k">while</span> <span class="n">fringe</span><span class="p">:</span> + <span class="n">n</span> <span class="o">=</span> <span class="n">fringe</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span> + <span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">=</span> <span class="n">n</span> + <span class="c1"># West</span> + <span class="k">if</span> <span class="n">nx</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> + <span class="k">if</span> <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">ny</span><span class="p">]</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">:</span> + <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">ny</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="n">fringe</span><span class="o">.</span><span class="n">appendleft</span><span class="p">((</span><span class="n">nx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">ny</span><span class="p">))</span> + <span class="c1"># East</span> + <span class="k">if</span> <span class="n">nx</span> <span class="o"><</span> <span class="n">sx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span> + <span class="k">if</span> <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">ny</span><span class="p">]</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">:</span> + <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">ny</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="n">fringe</span><span class="o">.</span><span class="n">appendleft</span><span class="p">((</span><span class="n">nx</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">ny</span><span class="p">))</span> + <span class="c1"># North</span> + <span class="k">if</span> <span class="n">ny</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> + <span class="k">if</span> <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">:</span> + <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="n">fringe</span><span class="o">.</span><span class="n">appendleft</span><span class="p">((</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))</span> + <span class="c1"># South</span> + <span class="k">if</span> <span class="n">ny</span> <span class="o"><</span> <span class="n">sy</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span> + <span class="k">if</span> <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">:</span> + <span class="n">pmap</span><span class="p">[</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="n">fringe</span><span class="o">.</span><span class="n">appendleft</span><span class="p">((</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> +</pre></div> +</div> +<p>This algotihm will fill the area bounded by the yellow lines starting +from a center point (e.g. (10, 20)) with zeros:</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">flood_fill</span><span class="p">((</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">),</span> <span class="n">map1</span><span class="p">)</span> +<span class="n">map_float</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">map1</span><span class="p">)</span><span class="o">/</span><span class="mf">10.0</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">map1</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">colorbar</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/lidar_to_grid_map_tutorial_12_0.png" src="../../../_images/lidar_to_grid_map_tutorial_12_0.png" /> +<p>Let’s use this flood fill on real data:</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">xyreso</span> <span class="o">=</span> <span class="mf">0.02</span> <span class="c1"># x-y grid resolution</span> +<span class="n">yawreso</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">radians</span><span class="p">(</span><span class="mf">3.1</span><span class="p">)</span> <span class="c1"># yaw angle resolution [rad]</span> +<span class="n">ang</span><span class="p">,</span> <span class="n">dist</span> <span class="o">=</span> <span class="n">file_read</span><span class="p">(</span><span class="s2">"lidar01.csv"</span><span class="p">)</span> +<span class="n">ox</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">ang</span><span class="p">)</span> <span class="o">*</span> <span class="n">dist</span> +<span class="n">oy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">ang</span><span class="p">)</span> <span class="o">*</span> <span class="n">dist</span> +<span class="n">pmap</span><span class="p">,</span> <span class="n">minx</span><span class="p">,</span> <span class="n">maxx</span><span class="p">,</span> <span class="n">miny</span><span class="p">,</span> <span class="n">maxy</span><span class="p">,</span> <span class="n">xyreso</span> <span class="o">=</span> <span class="n">lg</span><span class="o">.</span><span class="n">generate_ray_casting_grid_map</span><span class="p">(</span><span class="n">ox</span><span class="p">,</span> <span class="n">oy</span><span class="p">,</span> <span class="n">xyreso</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span> +<span class="n">xyres</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">pmap</span><span class="p">)</span><span class="o">.</span><span class="n">shape</span> +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">122</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">pmap</span><span class="p">,</span> <span class="n">cmap</span> <span class="o">=</span> <span class="s2">"PiYG_r"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">clim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.4</span><span class="p">,</span> <span class="mf">1.4</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">gca</span><span class="p">()</span><span class="o">.</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="o">-</span><span class="mf">.5</span><span class="p">,</span> <span class="n">xyres</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">1</span><span class="p">),</span> <span class="n">minor</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">gca</span><span class="p">()</span><span class="o">.</span><span class="n">set_yticks</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="o">-</span><span class="mf">.5</span><span class="p">,</span> <span class="n">xyres</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">1</span><span class="p">),</span> <span class="n">minor</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s2">"minor"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"w"</span><span class="p">,</span> <span class="n">linewidth</span> <span class="o">=</span> <span class="mf">.6</span><span class="p">,</span> <span class="n">alpha</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">colorbar</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">The</span> <span class="n">grid</span> <span class="nb">map</span> <span class="ow">is</span> <span class="mi">150</span> <span class="n">x</span> <span class="mi">100</span> <span class="o">.</span> +</pre></div> +</div> +<img alt="../../../_images/lidar_to_grid_map_tutorial_14_1.png" src="../../../_images/lidar_to_grid_map_tutorial_14_1.png" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../ray_casting_grid_map/ray_casting_grid_map.html" class="btn btn-neutral float-left" title="Ray casting grid map" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../point_cloud_sampling/point_cloud_sampling.html" class="btn btn-neutral float-right" title="Point cloud Sampling" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/mapping.html b/modules/mapping/mapping.html new file mode 100644 index 00000000000..e985cc48faa --- /dev/null +++ b/modules/mapping/mapping.html @@ -0,0 +1,186 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Mapping — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Gaussian grid map" href="gaussian_grid_map/gaussian_grid_map.html" /> + <link rel="prev" title="Particle filter localization" href="../localization/particle_filter_localization/particle_filter_localization.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Mapping</a><ul> +<li class="toctree-l2"><a class="reference internal" href="gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Mapping</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/mapping_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="mapping"> +<span id="id1"></span><h1>Mapping<a class="headerlink" href="#mapping" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l1"><a class="reference internal" href="ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a><ul> +<li class="toctree-l2"><a class="reference internal" href="ndt_map/ndt_map.html#normal-distribution">Normal Distribution</a></li> +<li class="toctree-l2"><a class="reference internal" href="ndt_map/ndt_map.html#normal-distance-transform-mapping-steps">Normal Distance Transform mapping steps</a></li> +<li class="toctree-l2"><a class="reference internal" href="ndt_map/ndt_map.html#api">API</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l1"><a class="reference internal" href="lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l1"><a class="reference internal" href="point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a><ul> +<li class="toctree-l2"><a class="reference internal" href="point_cloud_sampling/point_cloud_sampling.html#voxel-point-sampling">Voxel Point Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="point_cloud_sampling/point_cloud_sampling.html#farthest-point-sampling">Farthest Point Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="point_cloud_sampling/point_cloud_sampling.html#poisson-disk-sampling">Poisson Disk Sampling</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l1"><a class="reference internal" href="circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l1"><a class="reference internal" href="rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a><ul> +<li class="toctree-l2"><a class="reference internal" href="rectangle_fitting/rectangle_fitting.html#step1-adaptive-range-segmentation">Step1: Adaptive range segmentation</a></li> +<li class="toctree-l2"><a class="reference internal" href="rectangle_fitting/rectangle_fitting.html#step2-rectangle-search">Step2: Rectangle search</a></li> +<li class="toctree-l2"><a class="reference internal" href="rectangle_fitting/rectangle_fitting.html#api">API</a></li> +<li class="toctree-l2"><a class="reference internal" href="rectangle_fitting/rectangle_fitting.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a><ul> +<li class="toctree-l2"><a class="reference internal" href="normal_vector_estimation/normal_vector_estimation.html#normal-vector-calculation-of-a-3d-triangle">Normal vector calculation of a 3D triangle</a></li> +<li class="toctree-l2"><a class="reference internal" href="normal_vector_estimation/normal_vector_estimation.html#normal-vector-estimation-with-randam-sampling-consensus-ransac">Normal vector estimation with RANdam SAmpling Consensus(RANSAC)</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../localization/particle_filter_localization/particle_filter_localization.html" class="btn btn-neutral float-left" title="Particle filter localization" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="gaussian_grid_map/gaussian_grid_map.html" class="btn btn-neutral float-right" title="Gaussian grid map" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/ndt_map/ndt_map.html b/modules/mapping/ndt_map/ndt_map.html new file mode 100644 index 00000000000..f127e932a4f --- /dev/null +++ b/modules/mapping/ndt_map/ndt_map.html @@ -0,0 +1,281 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Normal Distance Transform (NDT) map — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Ray casting grid map" href="../ray_casting_grid_map/ray_casting_grid_map.html" /> + <link rel="prev" title="Gaussian grid map" href="../gaussian_grid_map/gaussian_grid_map.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Normal Distance Transform (NDT) map</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#normal-distribution">Normal Distribution</a></li> +<li class="toctree-l3"><a class="reference internal" href="#normal-distance-transform-mapping-steps">Normal Distance Transform mapping steps</a></li> +<li class="toctree-l3"><a class="reference internal" href="#api">API</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Normal Distance Transform (NDT) map</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/ndt_map/ndt_map_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="normal-distance-transform-ndt-map"> +<span id="ndt-map"></span><h1>Normal Distance Transform (NDT) map<a class="headerlink" href="#normal-distance-transform-ndt-map" title="Permalink to this headline"></a></h1> +<p>This is a NDT mapping example.</p> +<p>Normal Distribution Transform (NDT) is a map representation that uses normal distribution for observation point modeling.</p> +<section id="normal-distribution"> +<h2>Normal Distribution<a class="headerlink" href="#normal-distribution" title="Permalink to this headline"></a></h2> +<p>Normal distribution consists of two parameters: mean <span class="math notranslate nohighlight">\(\mu\)</span> and covariance <span class="math notranslate nohighlight">\(\Sigma\)</span>.</p> +<p><span class="math notranslate nohighlight">\(\mathbf{X} \sim \mathcal{N}(\boldsymbol{\mu}, \boldsymbol{\Sigma})\)</span></p> +<p>In the 2D case, <span class="math notranslate nohighlight">\(\boldsymbol{\mu}\)</span> is a 2D vector and <span class="math notranslate nohighlight">\(\boldsymbol{\Sigma}\)</span> is a 2x2 matrix.</p> +<p>In the matrix form, the probability density function of thr normal distribution is:</p> +<p><span class="math notranslate nohighlight">\(X=\frac{1}{\sqrt{(2 \pi)^2|\Sigma|}} \exp \left\{-\frac{1}{2}^t(x-\mu) \sum^{-1}(x-\mu)\right\}\)</span></p> +</section> +<section id="normal-distance-transform-mapping-steps"> +<h2>Normal Distance Transform mapping steps<a class="headerlink" href="#normal-distance-transform-mapping-steps" title="Permalink to this headline"></a></h2> +<p>NDT mapping consists of two steps:</p> +<p>When we have a new observation like this:</p> +<figure class="align-default"> +<img alt="../../../_images/raw_observations.png" src="../../../_images/raw_observations.png" /> +</figure> +<p>First, we need to cluster the observation points. +This is done by using a grid based clustering algorithm.</p> +<p>The result is:</p> +<figure class="align-default"> +<img alt="../../../_images/grid_clustering.png" src="../../../_images/grid_clustering.png" /> +</figure> +<p>Then, we need to fit a normal distribution to each grid cluster.</p> +<p>Black ellipse shows each NDT grid like this:</p> +<figure class="align-default"> +<img alt="../../../_images/ndt_map1.png" src="../../../_images/ndt_map1.png" /> +</figure> +<figure class="align-default"> +<img alt="../../../_images/ndt_map2.png" src="../../../_images/ndt_map2.png" /> +</figure> +</section> +<section id="api"> +<h2>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h2> +<dl class="py class"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap"> +<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">Mapping.ndt_map.ndt_map.</span></span><span class="sig-name descname"><span class="pre">NDTMap</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ox</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">oy</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">resolution</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/ndt_map/ndt_map.html#NDTMap"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap" title="Permalink to this definition"></a></dt> +<dd><p>Normal Distribution Transform (NDT) map class</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>ox</strong> – obstacle x position list</p></li> +<li><p><strong>oy</strong> – obstacle y position list</p></li> +<li><p><strong>resolution</strong> – grid resolution [m]</p></li> +</ul> +</dd> +</dl> +<dl class="py class"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid"> +<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">NDTGrid</span></span><a class="reference internal" href="../../../_modules/Mapping/ndt_map/ndt_map.html#NDTMap.NDTGrid"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid" title="Permalink to this definition"></a></dt> +<dd><p>NDT grid</p> +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.center_grid_x"> +<span class="sig-name descname"><span class="pre">center_grid_x</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.center_grid_x" title="Permalink to this definition"></a></dt> +<dd><p>Center x position of the NDT grid</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.center_grid_y"> +<span class="sig-name descname"><span class="pre">center_grid_y</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.center_grid_y" title="Permalink to this definition"></a></dt> +<dd><p>Center y position of the NDT grid</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.covariance"> +<span class="sig-name descname"><span class="pre">covariance</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.covariance" title="Permalink to this definition"></a></dt> +<dd><p>Covariance matrix of the NDT grid</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.eig_values"> +<span class="sig-name descname"><span class="pre">eig_values</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.eig_values" title="Permalink to this definition"></a></dt> +<dd><p>Eigen values of the NDT grid</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.eig_vec"> +<span class="sig-name descname"><span class="pre">eig_vec</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.eig_vec" title="Permalink to this definition"></a></dt> +<dd><p>Eigen vectors of the NDT grid</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.mean_x"> +<span class="sig-name descname"><span class="pre">mean_x</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.mean_x" title="Permalink to this definition"></a></dt> +<dd><p>Mean x position of points in the NDTGrid cell</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.mean_y"> +<span class="sig-name descname"><span class="pre">mean_y</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.mean_y" title="Permalink to this definition"></a></dt> +<dd><p>Mean y position of points in the NDTGrid cell</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.n_points"> +<span class="sig-name descname"><span class="pre">n_points</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.NDTGrid.n_points" title="Permalink to this definition"></a></dt> +<dd><p>Number of points in the NDTGrid grid</p> +</dd></dl> + +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.grid_index_map"> +<span class="sig-name descname"><span class="pre">grid_index_map</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.grid_index_map" title="Permalink to this definition"></a></dt> +<dd><p>NDT grid index map</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.min_n_points"> +<span class="sig-name descname"><span class="pre">min_n_points</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.min_n_points" title="Permalink to this definition"></a></dt> +<dd><p>Minimum number of points in the NDT grid</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.ndt_map.ndt_map.NDTMap.resolution"> +<span class="sig-name descname"><span class="pre">resolution</span></span><a class="headerlink" href="#Mapping.ndt_map.ndt_map.NDTMap.resolution" title="Permalink to this definition"></a></dt> +<dd><p>Resolution of the NDT grid [m]</p> +</dd></dl> + +</dd></dl> + +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../gaussian_grid_map/gaussian_grid_map.html" class="btn btn-neutral float-left" title="Gaussian grid map" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../ray_casting_grid_map/ray_casting_grid_map.html" class="btn btn-neutral float-right" title="Ray casting grid map" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/normal_vector_estimation/normal_vector_estimation.html b/modules/mapping/normal_vector_estimation/normal_vector_estimation.html new file mode 100644 index 00000000000..be732605524 --- /dev/null +++ b/modules/mapping/normal_vector_estimation/normal_vector_estimation.html @@ -0,0 +1,261 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Normal vector estimation — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="SLAM" href="../../slam/slam.html" /> + <link rel="prev" title="Object shape recognition using rectangle fitting" href="../rectangle_fitting/rectangle_fitting.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Normal vector estimation</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#normal-vector-calculation-of-a-3d-triangle">Normal vector calculation of a 3D triangle</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#api">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#normal-vector-estimation-with-randam-sampling-consensus-ransac">Normal vector estimation with RANdam SAmpling Consensus(RANSAC)</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#id1">API</a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Normal vector estimation</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/normal_vector_estimation/normal_vector_estimation_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="normal-vector-estimation"> +<h1>Normal vector estimation<a class="headerlink" href="#normal-vector-estimation" title="Permalink to this headline"></a></h1> +<section id="normal-vector-calculation-of-a-3d-triangle"> +<h2>Normal vector calculation of a 3D triangle<a class="headerlink" href="#normal-vector-calculation-of-a-3d-triangle" title="Permalink to this headline"></a></h2> +<p>A 3D point is as a vector:</p> +<div class="math notranslate nohighlight"> +\[p = [x, y, z]\]</div> +<p>When there are 3 points in 3D space, <span class="math notranslate nohighlight">\(p_1, p_2, p_3\)</span>,</p> +<p>we can calculate a normal vector n of a 3D triangle which is consisted of the points.</p> +<div class="math notranslate nohighlight"> +\[n = \frac{v1 \times v2}{|v1 \times v2|}\]</div> +<p>where</p> +<div class="math notranslate nohighlight"> +\[v1 = p2 - p1\]</div> +<div class="math notranslate nohighlight"> +\[v2 = p3 - p1\]</div> +<p>This is an example of normal vector calculation:</p> +<figure class="align-default"> +<img alt="../../../_images/normal_vector_calc.png" src="../../../_images/normal_vector_calc.png" /> +</figure> +<section id="api"> +<h3>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="Mapping.normal_vector_estimation.normal_vector_estimation.calc_normal_vector"> +<span class="sig-prename descclassname"><span class="pre">Mapping.normal_vector_estimation.normal_vector_estimation.</span></span><span class="sig-name descname"><span class="pre">calc_normal_vector</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">p1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">p2</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">p3</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/normal_vector_estimation/normal_vector_estimation.html#calc_normal_vector"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.normal_vector_estimation.normal_vector_estimation.calc_normal_vector" title="Permalink to this definition"></a></dt> +<dd><p>Calculate normal vector of triangle</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>p1</strong> (<em>np.array</em>) – 3D point</p></li> +<li><p><strong>p2</strong> (<em>np.array</em>) – 3D point</p></li> +<li><p><strong>p3</strong> (<em>np.array</em>) – 3D point</p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><strong>normal_vector</strong> – normal vector (3,)</p> +</dd> +<dt class="field-odd">Return type</dt> +<dd class="field-odd"><p>np.array</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +<section id="normal-vector-estimation-with-randam-sampling-consensus-ransac"> +<h2>Normal vector estimation with RANdam SAmpling Consensus(RANSAC)<a class="headerlink" href="#normal-vector-estimation-with-randam-sampling-consensus-ransac" title="Permalink to this headline"></a></h2> +<p>Consider the problem of estimating the normal vector of a plane based on a +set of N 3D points where a plane can be observed.</p> +<p>There is a way that uses all point cloud data to estimate a plane and +a normal vector using the <a class="reference external" href="https://stackoverflow.com/a/44315221/8387766">least-squares method</a></p> +<p>However, this method is vulnerable to noise of the point cloud.</p> +<p>In this document, we will use a method that uses +<a class="reference external" href="https://en.wikipedia.org/wiki/Random_sample_consensus">RANdam SAmpling Consensus(RANSAC)</a> +to estimate a plane and a normal vector.</p> +<p>RANSAC is a robust estimation methods for data set with outliers.</p> +<p>This RANSAC based normal vector estimation method is as follows:</p> +<ol class="arabic simple"> +<li><p>Select 3 points randomly from the point cloud.</p></li> +<li><p>Calculate a normal vector of a plane which is consists of the sampled 3 points.</p></li> +<li><p>Calculate the distance between the calculated plane and the all point cloud.</p></li> +<li><p>If the distance is less than a threshold, the point is considered to be an inlier.</p></li> +<li><p>Repeat the above steps until the inlier ratio is greater than a threshold.</p></li> +</ol> +<p>This is an example of RANSAC based normal vector estimation:</p> +<figure class="align-default"> +<img alt="../../../_images/ransac_normal_vector_estimation.png" src="../../../_images/ransac_normal_vector_estimation.png" /> +</figure> +<section id="id1"> +<h3>API<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="Mapping.normal_vector_estimation.normal_vector_estimation.ransac_normal_vector_estimation"> +<span class="sig-prename descclassname"><span class="pre">Mapping.normal_vector_estimation.normal_vector_estimation.</span></span><span class="sig-name descname"><span class="pre">ransac_normal_vector_estimation</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">points_3d</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">inlier_radio_th</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0.7</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">inlier_dist</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0.1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">p</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0.99</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/normal_vector_estimation/normal_vector_estimation.html#ransac_normal_vector_estimation"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.normal_vector_estimation.normal_vector_estimation.ransac_normal_vector_estimation" title="Permalink to this definition"></a></dt> +<dd><p>RANSAC based normal vector estimation</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>points_3d</strong> (<em>np.array</em>) – 3D points (N, 3)</p></li> +<li><p><strong>inlier_radio_th</strong> (<em>float</em>) – Inlier ratio threshold. If inlier ratio is larger than this value, +the iteration is stopped. Default is 0.7.</p></li> +<li><p><strong>inlier_dist</strong> (<em>float</em>) – Inlier distance threshold. If distance between points and estimated +plane is smaller than this value, the point is inlier. Default is 0.1.</p></li> +<li><p><strong>p</strong> (<em>float</em>) – Probability that at least one of the sets of random samples does not +include an outlier. If this probability is near 1, the iteration +number is large. Default is 0.99.</p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><ul class="simple"> +<li><p><strong>center_vector</strong> (<em>np.array</em>) – Center of estimated plane. (3,)</p></li> +<li><p><strong>normal_vector</strong> (<em>np.array</em>) – Normal vector of estimated plane. (3,)</p></li> +</ul> +</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../rectangle_fitting/rectangle_fitting.html" class="btn btn-neutral float-left" title="Object shape recognition using rectangle fitting" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../slam/slam.html" class="btn btn-neutral float-right" title="SLAM" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/point_cloud_sampling/point_cloud_sampling.html b/modules/mapping/point_cloud_sampling/point_cloud_sampling.html new file mode 100644 index 00000000000..bd8f49351a8 --- /dev/null +++ b/modules/mapping/point_cloud_sampling/point_cloud_sampling.html @@ -0,0 +1,289 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Point cloud Sampling — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="k-means object clustering" href="../k_means_object_clustering/k_means_object_clustering.html" /> + <link rel="prev" title="Lidar to grid map" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Point cloud Sampling</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#voxel-point-sampling">Voxel Point Sampling</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#api">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#farthest-point-sampling">Farthest Point Sampling</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#id2">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#poisson-disk-sampling">Poisson Disk Sampling</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#id3">API</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Point cloud Sampling</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/point_cloud_sampling/point_cloud_sampling_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="point-cloud-sampling"> +<span id="id1"></span><h1>Point cloud Sampling<a class="headerlink" href="#point-cloud-sampling" title="Permalink to this headline"></a></h1> +<p>This sections explains point cloud sampling algorithms in PythonRobotics.</p> +<p>Point clouds are two-dimensional and three-dimensional based data +acquired by external sensors like LIDAR, cameras, etc. +In general, Point Cloud data is very large in number of data. +So, if you process all the data, computation time might become an issue.</p> +<p>Point cloud sampling is a technique for solving this computational complexity +issue by extracting only representative point data and thinning the point +cloud data without compromising the performance of processing using the point +cloud data.</p> +<section id="voxel-point-sampling"> +<h2>Voxel Point Sampling<a class="headerlink" href="#voxel-point-sampling" title="Permalink to this headline"></a></h2> +<figure class="align-default"> +<img alt="../../../_images/voxel_point_sampling.png" src="../../../_images/voxel_point_sampling.png" /> +</figure> +<p>Voxel grid sampling is a method of reducing point cloud data by using the +<a class="reference external" href="https://en.wikipedia.org/wiki/Voxel">Voxel grids</a> which is regular grids +in three-dimensional space.</p> +<p>This method determines which each point is in a grid, and replaces the point +clouds that are in the same Voxel with their average to reduce the number of +points.</p> +<section id="api"> +<h3>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="Mapping.point_cloud_sampling.point_cloud_sampling.voxel_point_sampling"> +<span class="sig-prename descclassname"><span class="pre">Mapping.point_cloud_sampling.point_cloud_sampling.</span></span><span class="sig-name descname"><span class="pre">voxel_point_sampling</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">original_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">numpy.ndarray</span><span class="p"><span class="pre">[</span></span><span class="pre">Any</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">numpy.dtype</span><span class="p"><span class="pre">[</span></span><span class="pre">numpy._typing._array_like._ScalarType_co</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">voxel_size</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">float</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/point_cloud_sampling/point_cloud_sampling.html#voxel_point_sampling"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.point_cloud_sampling.point_cloud_sampling.voxel_point_sampling" title="Permalink to this definition"></a></dt> +<dd><p>Voxel Point Sampling function. +This function sample N-dimensional points with voxel grid. +Points in a same voxel grid will be merged by mean operation for sampling.</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>original_points</strong> (<em>(</em><em>M</em><em>, </em><em>N</em><em>) </em><em>N-dimensional points for sampling.</em>) – The number of points is M.</p></li> +<li><p><strong>voxel_size</strong> (<em>voxel grid size</em>) – </p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p></p> +</dd> +<dt class="field-odd">Return type</dt> +<dd class="field-odd"><p>sampled points (M’, N)</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +<section id="farthest-point-sampling"> +<h2>Farthest Point Sampling<a class="headerlink" href="#farthest-point-sampling" title="Permalink to this headline"></a></h2> +<figure class="align-default"> +<img alt="../../../_images/farthest_point_sampling.png" src="../../../_images/farthest_point_sampling.png" /> +</figure> +<p>Farthest Point Sampling is a point cloud sampling method by a specified +number of points so that the distance between points is as far from as +possible.</p> +<p>This method is useful for machine learning and other situations where +you want to obtain a specified number of points from point cloud.</p> +<section id="id2"> +<h3>API<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="Mapping.point_cloud_sampling.point_cloud_sampling.farthest_point_sampling"> +<span class="sig-prename descclassname"><span class="pre">Mapping.point_cloud_sampling.point_cloud_sampling.</span></span><span class="sig-name descname"><span class="pre">farthest_point_sampling</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">orig_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">numpy.ndarray</span><span class="p"><span class="pre">[</span></span><span class="pre">Any</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">numpy.dtype</span><span class="p"><span class="pre">[</span></span><span class="pre">numpy._typing._array_like._ScalarType_co</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">n_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">seed</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/point_cloud_sampling/point_cloud_sampling.html#farthest_point_sampling"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.point_cloud_sampling.point_cloud_sampling.farthest_point_sampling" title="Permalink to this definition"></a></dt> +<dd><p>Farthest point sampling function +This function sample N-dimensional points with the farthest point policy.</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>orig_points</strong> (<em>(</em><em>M</em><em>, </em><em>N</em><em>) </em><em>N-dimensional points for sampling.</em>) – The number of points is M.</p></li> +<li><p><strong>n_points</strong> (<em>number of points for sampling</em>) – </p></li> +<li><p><strong>seed</strong> (<em>random seed number</em>) – </p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p></p> +</dd> +<dt class="field-odd">Return type</dt> +<dd class="field-odd"><p>sampled points (n_points, N)</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +<section id="poisson-disk-sampling"> +<h2>Poisson Disk Sampling<a class="headerlink" href="#poisson-disk-sampling" title="Permalink to this headline"></a></h2> +<figure class="align-default"> +<img alt="../../../_images/poisson_disk_sampling.png" src="../../../_images/poisson_disk_sampling.png" /> +</figure> +<p>Poisson disk sample is a point cloud sampling method by a specified +number of points so that the algorithm selects points where the distance +from selected points is greater than a certain distance.</p> +<p>Although this method does not have good performance comparing the Farthest +distance sample where each point is distributed farther from each other, +this is suitable for real-time processing because of its fast computation time.</p> +<section id="id3"> +<h3>API<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="Mapping.point_cloud_sampling.point_cloud_sampling.poisson_disk_sampling"> +<span class="sig-prename descclassname"><span class="pre">Mapping.point_cloud_sampling.point_cloud_sampling.</span></span><span class="sig-name descname"><span class="pre">poisson_disk_sampling</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">orig_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">numpy.ndarray</span><span class="p"><span class="pre">[</span></span><span class="pre">Any</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">numpy.dtype</span><span class="p"><span class="pre">[</span></span><span class="pre">numpy._typing._array_like._ScalarType_co</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">n_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">min_distance</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">float</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">seed</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">MAX_ITER</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1000</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/point_cloud_sampling/point_cloud_sampling.html#poisson_disk_sampling"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.point_cloud_sampling.point_cloud_sampling.poisson_disk_sampling" title="Permalink to this definition"></a></dt> +<dd><p>Poisson disk sampling function +This function sample N-dimensional points randomly until the number of +points keeping minimum distance between selected points.</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>orig_points</strong> (<em>(</em><em>M</em><em>, </em><em>N</em><em>) </em><em>N-dimensional points for sampling.</em>) – The number of points is M.</p></li> +<li><p><strong>n_points</strong> (<em>number of points for sampling</em>) – </p></li> +<li><p><strong>min_distance</strong> (<em>minimum distance between selected points.</em>) – </p></li> +<li><p><strong>seed</strong> (<em>random seed number</em>) – </p></li> +<li><p><strong>MAX_ITER</strong> (<em>Maximum number of iteration. Default is 1000.</em>) – </p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p></p> +</dd> +<dt class="field-odd">Return type</dt> +<dd class="field-odd"><p>sampled points (n_points or less, N)</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html" class="btn btn-neutral float-left" title="Lidar to grid map" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../k_means_object_clustering/k_means_object_clustering.html" class="btn btn-neutral float-right" title="k-means object clustering" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/ray_casting_grid_map/ray_casting_grid_map.html b/modules/mapping/ray_casting_grid_map/ray_casting_grid_map.html new file mode 100644 index 00000000000..1a8f5b2660a --- /dev/null +++ b/modules/mapping/ray_casting_grid_map/ray_casting_grid_map.html @@ -0,0 +1,155 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Ray casting grid map — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Lidar to grid map" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html" /> + <link rel="prev" title="Normal Distance Transform (NDT) map" href="../ndt_map/ndt_map.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rectangle_fitting/rectangle_fitting.html">Object shape recognition using rectangle fitting</a></li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Ray casting grid map</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/ray_casting_grid_map/ray_casting_grid_map_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="ray-casting-grid-map"> +<h1>Ray casting grid map<a class="headerlink" href="#ray-casting-grid-map" title="Permalink to this headline"></a></h1> +<p>This is a 2D ray casting grid mapping example.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/raycasting_grid_map/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/raycasting_grid_map/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../ndt_map/ndt_map.html" class="btn btn-neutral float-left" title="Normal Distance Transform (NDT) map" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html" class="btn btn-neutral float-right" title="Lidar to grid map" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/mapping/rectangle_fitting/rectangle_fitting.html b/modules/mapping/rectangle_fitting/rectangle_fitting.html new file mode 100644 index 00000000000..bf918da0880 --- /dev/null +++ b/modules/mapping/rectangle_fitting/rectangle_fitting.html @@ -0,0 +1,283 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Object shape recognition using rectangle fitting — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Normal vector estimation" href="../normal_vector_estimation/normal_vector_estimation.html" /> + <link rel="prev" title="Object shape recognition using circle fitting" href="../circle_fitting/circle_fitting.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../mapping.html">Mapping</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../gaussian_grid_map/gaussian_grid_map.html">Gaussian grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ndt_map/ndt_map.html">Normal Distance Transform (NDT) map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ray_casting_grid_map/ray_casting_grid_map.html">Ray casting grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial.html">Lidar to grid map</a></li> +<li class="toctree-l2"><a class="reference internal" href="../point_cloud_sampling/point_cloud_sampling.html">Point cloud Sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="../k_means_object_clustering/k_means_object_clustering.html">k-means object clustering</a></li> +<li class="toctree-l2"><a class="reference internal" href="../circle_fitting/circle_fitting.html">Object shape recognition using circle fitting</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Object shape recognition using rectangle fitting</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#step1-adaptive-range-segmentation">Step1: Adaptive range segmentation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step2-rectangle-search">Step2: Rectangle search</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#rectangle-area-minimization-criteria">1. Rectangle Area Minimization criteria</a></li> +<li class="toctree-l4"><a class="reference internal" href="#closeness-criteria">2. Closeness criteria</a></li> +<li class="toctree-l4"><a class="reference internal" href="#variance-criteria">3. Variance criteria</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#api">API</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../normal_vector_estimation/normal_vector_estimation.html">Normal vector estimation</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../mapping.html">Mapping</a> »</li> + <li>Object shape recognition using rectangle fitting</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/mapping/rectangle_fitting/rectangle_fitting_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="object-shape-recognition-using-rectangle-fitting"> +<h1>Object shape recognition using rectangle fitting<a class="headerlink" href="#object-shape-recognition-using-rectangle-fitting" title="Permalink to this headline"></a></h1> +<p>This is an object shape recognition using rectangle fitting.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/rectangle_fitting/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/Mapping/rectangle_fitting/animation.gif" /> +<p>This example code is based on this paper algorithm:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.ri.cmu.edu/publications/efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners">Efficient L-Shape Fitting for Vehicle Detection Using Laser Scanners - The Robotics Institute Carnegie Mellon University</a></p></li> +</ul> +<p>The algorithm consists of 2 steps as below.</p> +<section id="step1-adaptive-range-segmentation"> +<h2>Step1: Adaptive range segmentation<a class="headerlink" href="#step1-adaptive-range-segmentation" title="Permalink to this headline"></a></h2> +<p>In the first step, all range data points are segmented into some clusters.</p> +<p>We calculate the distance between each range data and the nearest range data, and if this distance is below a certain threshold, it is judged to be in the same cluster. +This distance threshold is determined in proportion to the distance from the sensor. +This is taking advantage of the general model of distance sensors, which tends to have sparser data distribution as the distance from the sensor increases.</p> +<p>The threshold range is calculated by:</p> +<div class="math notranslate nohighlight"> +\[r_{th} = R_0 + R_d * r_{origin}\]</div> +<p>where</p> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(r_{th}\)</span>: Threashold range</p></li> +<li><p><span class="math notranslate nohighlight">\(R_0, R_d\)</span>: Constant parameters</p></li> +<li><p><span class="math notranslate nohighlight">\(r_{origin}\)</span>: Distance from the sensor for a range data.</p></li> +</ul> +</section> +<section id="step2-rectangle-search"> +<h2>Step2: Rectangle search<a class="headerlink" href="#step2-rectangle-search" title="Permalink to this headline"></a></h2> +<p>In the second step, for each cluster calculated in the previous step, rectangular fittings will be applied. +In this rectangular fitting, each cluster’s distance data is rotated at certain angle intervals. +It is evaluated by one of the three evaluation functions below, then best angle parameter one is selected as the rectangle shape.</p> +<section id="rectangle-area-minimization-criteria"> +<h3>1. Rectangle Area Minimization criteria<a class="headerlink" href="#rectangle-area-minimization-criteria" title="Permalink to this headline"></a></h3> +<p>This evaluation function calculates the area of the smallest rectangle that includes all the points, derived from the difference between the maximum and minimum values on the x-y axis for all distance data points. +This allows for fitting a rectangle in a direction that encompasses as much of the smallest rectangular shape as possible.</p> +</section> +<section id="closeness-criteria"> +<h3>2. Closeness criteria<a class="headerlink" href="#closeness-criteria" title="Permalink to this headline"></a></h3> +<p>This evaluation function uses the distances between the top and bottom vertices on the right side of the rectangle and each point in the distance data as evaluation values. +If there are points on the rectangle edges, this evaluation value decreases.</p> +</section> +<section id="variance-criteria"> +<h3>3. Variance criteria<a class="headerlink" href="#variance-criteria" title="Permalink to this headline"></a></h3> +<p>This evaluation function uses the squreed distances between the edges of the rectangle (horizontal and vertical) and each point. +Calculating the squared error is the same as calculating the variance. +The smaller this variance, the more it signifies that the points fit within the rectangle.</p> +</section> +</section> +<section id="api"> +<h2>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h2> +<dl class="py class"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting"> +<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">Mapping.rectangle_fitting.rectangle_fitting.</span></span><span class="sig-name descname"><span class="pre">LShapeFitting</span></span><a class="reference internal" href="../../../_modules/Mapping/rectangle_fitting/rectangle_fitting.html#LShapeFitting"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting" title="Permalink to this definition"></a></dt> +<dd><p>LShapeFitting class. You can use this class by initializing the class and +changing the parameters, and then calling the fitting method.</p> +<dl class="py class"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Criteria"> +<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">Criteria</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">value</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/rectangle_fitting/rectangle_fitting.html#LShapeFitting.Criteria"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Criteria" title="Permalink to this definition"></a></dt> +<dd><p>An enumeration.</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.R0"> +<span class="sig-name descname"><span class="pre">R0</span></span><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.R0" title="Permalink to this definition"></a></dt> +<dd><p>Range segmentation parameter [m]</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Rd"> +<span class="sig-name descname"><span class="pre">Rd</span></span><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.Rd" title="Permalink to this definition"></a></dt> +<dd><p>Range segmentation parameter [m]</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.criteria"> +<span class="sig-name descname"><span class="pre">criteria</span></span><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.criteria" title="Permalink to this definition"></a></dt> +<dd><p>Fitting criteria parameter</p> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.d_theta_deg_for_search"> +<span class="sig-name descname"><span class="pre">d_theta_deg_for_search</span></span><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.d_theta_deg_for_search" title="Permalink to this definition"></a></dt> +<dd><p>Angle difference parameter [deg]</p> +</dd></dl> + +<dl class="py method"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.fitting"> +<span class="sig-name descname"><span class="pre">fitting</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ox</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">oy</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/Mapping/rectangle_fitting/rectangle_fitting.html#LShapeFitting.fitting"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.fitting" title="Permalink to this definition"></a></dt> +<dd><p>Fitting L-shape model to object points</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>ox</strong> (<em>x positions of range points from an object</em>) – </p></li> +<li><p><strong>oy</strong> (<em>y positions of range points from an object</em>) – </p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><ul class="simple"> +<li><p><strong>rects</strong> (<em>Fitting rectangles</em>)</p></li> +<li><p><strong>id_sets</strong> (<em>id sets of each cluster</em>)</p></li> +</ul> +</p> +</dd> +</dl> +</dd></dl> + +<dl class="py attribute"> +<dt class="sig sig-object py" id="Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.min_dist_of_closeness_criteria"> +<span class="sig-name descname"><span class="pre">min_dist_of_closeness_criteria</span></span><a class="headerlink" href="#Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting.min_dist_of_closeness_criteria" title="Permalink to this definition"></a></dt> +<dd><p>Minimum distance for closeness criteria parameter [m]</p> +</dd></dl> + +</dd></dl> + +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.ri.cmu.edu/publications/efficient-l-shape-fitting-for-vehicle-detection-using-laser-scanners">Efficient L-Shape Fitting for Vehicle Detection Using Laser Scanners - The Robotics Institute Carnegie Mellon University</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../circle_fitting/circle_fitting.html" class="btn btn-neutral float-left" title="Object shape recognition using circle fitting" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../normal_vector_estimation/normal_vector_estimation.html" class="btn btn-neutral float-right" title="Normal vector estimation" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/bezier_path/bezier_path.html b/modules/path_planning/bezier_path/bezier_path.html new file mode 100644 index 00000000000..d8bd37c7879 --- /dev/null +++ b/modules/path_planning/bezier_path/bezier_path.html @@ -0,0 +1,177 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Bezier path planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Quintic polynomials planning" href="../quintic_polynomials_planner/quintic_polynomials_planner.html" /> + <link rel="prev" title="Eta^3 Spline path planning" href="../eta3_spline/eta3_spline.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Bezier path planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/bezier_path/bezier_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="bezier-path-planning"> +<h1>Bezier path planning<a class="headerlink" href="#bezier-path-planning" title="Permalink to this headline"></a></h1> +<p>A sample code of Bezier path planning.</p> +<p>It is based on 4 control points Beizer path.</p> +<img alt="../../../_images/Figure_1.png" src="../../../_images/Figure_1.png" /> +<p>If you change the offset distance from start and end point,</p> +<p>You can get different Beizer course:</p> +<img alt="../../../_images/Figure_2.png" src="../../../_images/Figure_2.png" /> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.294.6438&rep=rep1&type=pdf">Continuous Curvature Path Generation Based on Bezier Curves for +Autonomous +Vehicles</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../eta3_spline/eta3_spline.html" class="btn btn-neutral float-left" title="Eta^3 Spline path planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../quintic_polynomials_planner/quintic_polynomials_planner.html" class="btn btn-neutral float-right" title="Quintic polynomials planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/bspline_path/bspline_path.html b/modules/path_planning/bspline_path/bspline_path.html new file mode 100644 index 00000000000..dc646678374 --- /dev/null +++ b/modules/path_planning/bspline_path/bspline_path.html @@ -0,0 +1,343 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>B-Spline planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Clothoid path planning" href="../clothoid_path/clothoid_path.html" /> + <link rel="prev" title="Cubic spline planning" href="../cubic_spline/cubic_spline.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">B-Spline planning</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#bspline-basics">Bspline basics</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bspline-interpolation-planning">Bspline interpolation planning</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#api">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#bspline-approximation-planning">Bspline approximation planning</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#id1">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>B-Spline planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/bspline_path/bspline_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="b-spline-planning"> +<h1>B-Spline planning<a class="headerlink" href="#b-spline-planning" title="Permalink to this headline"></a></h1> +<img alt="../../../_images/bspline_path_planning.png" src="../../../_images/bspline_path_planning.png" /> +<p>This is a B-Spline path planning routines.</p> +<p>If you input waypoints, it generates a smooth path with B-Spline curve.</p> +<p>This codes provide two types of B-Spline curve generations:</p> +<ol class="arabic simple"> +<li><p>Interpolation: generate a curve that passes through all waypoints.</p></li> +<li><p>Approximation: generate a curve that approximates the waypoints. (Not passing through all waypoints)</p></li> +</ol> +<section id="bspline-basics"> +<h2>Bspline basics<a class="headerlink" href="#bspline-basics" title="Permalink to this headline"></a></h2> +<p>BSpline (Basis-Spline) is a piecewise polynomial spline curve.</p> +<p>It is expressed by the following equation.</p> +<p><span class="math notranslate nohighlight">\(\mathbf{S}(x)=\sum_{i=k-p}^k \mathbf{c}_i B_{i, p}(x)\)</span></p> +<p>here:</p> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(S(x)\)</span> is the curve point on the spline at x.</p></li> +<li><p><span class="math notranslate nohighlight">\(c_i\)</span> is the representative point generating the spline, called the control point.</p></li> +<li><p><span class="math notranslate nohighlight">\(p+1\)</span> is the dimension of the BSpline.</p></li> +<li><p><span class="math notranslate nohighlight">\(k\)</span> is the number of knots.</p></li> +<li><p><span class="math notranslate nohighlight">\(B_{i,p}(x)\)</span> is a function called Basis Function.</p></li> +</ul> +<p>The the basis function can be calculated by the following <a class="reference external" href="https://en.wikipedia.org/wiki/De_Boor%27s_algorithm">De Boor recursion formula</a>:</p> +<p><span class="math notranslate nohighlight">\(B_{i, 0}(x):= \begin{cases}1 & \text { if } \quad t_i \leq x<t_{i+1} \\ 0 & \text { otherwise }\end{cases}\)</span></p> +<p><span class="math notranslate nohighlight">\(B_{i, p}(x):=\frac{x-t_i}{t_{i+p}-t_i} B_{i, p-1}(x)+\frac{t_{i+p+1}-x}{t_{i+p+1}-t_{i+1}} B_{i+1, p-1}(x)\)</span></p> +<p>here:</p> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(t_i\)</span> is each element of the knot vector.</p></li> +</ul> +<p>This figure shows the BSpline basis functions for each of <span class="math notranslate nohighlight">\(i\)</span>:</p> +<img alt="../../../_images/basis_functions.png" src="../../../_images/basis_functions.png" /> +<p>Note that when all the basis functions are added together, summation is 1.0 for any x value.</p> +<p>This means that the result curve is smooth when each control point is weighted addition by this basis function,</p> +<p>This code is for generating the upper basis function graph using <a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.BSpline.html">scipy</a>.</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">scipy.interpolate</span> <span class="kn">import</span> <span class="n">BSpline</span> + +<span class="k">def</span> <span class="nf">B_orig</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">t</span><span class="p">):</span> + <span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> + <span class="k">return</span> <span class="mf">1.0</span> <span class="k">if</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o"><=</span> <span class="n">x</span> <span class="o"><</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="mf">0.0</span> + <span class="k">if</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">k</span><span class="p">]</span> <span class="o">==</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span> + <span class="n">c1</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">c1</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">k</span><span class="p">]</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">*</span> <span class="n">B</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">k</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> + + <span class="k">if</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]:</span> + <span class="n">c2</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">c2</span> <span class="o">=</span> <span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">x</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">*</span> <span class="n">B</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">k</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> + <span class="k">return</span> <span class="n">c1</span> <span class="o">+</span> <span class="n">c2</span> + + +<span class="k">def</span> <span class="nf">B</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">t</span><span class="p">):</span> + <span class="n">c</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros_like</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> + <span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> + <span class="k">return</span> <span class="n">BSpline</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">k</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span> + + +<span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + <span class="n">k</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1"># degree of the spline</span> + <span class="n">t</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span> <span class="c1"># knots vector</span> + + <span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> + <span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">r_</span><span class="p">[[</span><span class="n">np</span><span class="o">.</span><span class="n">min</span><span class="p">(</span><span class="n">t</span><span class="p">)]</span><span class="o">*</span><span class="n">k</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">t</span><span class="p">)]</span><span class="o">*</span><span class="n">k</span><span class="p">]</span> + + <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> <span class="o">-</span> <span class="n">k</span> <span class="o">-</span> <span class="mi">1</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> + <span class="n">y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">B</span><span class="p">(</span><span class="n">ix</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> <span class="k">for</span> <span class="n">ix</span> <span class="ow">in</span> <span class="n">x</span><span class="p">])</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s1">'i = </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Basis functions (k = </span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s1">, knots = </span><span class="si">{</span><span class="n">t</span><span class="si">}</span><span class="s1">)'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +</section> +<section id="bspline-interpolation-planning"> +<h2>Bspline interpolation planning<a class="headerlink" href="#bspline-interpolation-planning" title="Permalink to this headline"></a></h2> +<p><a class="reference internal" href="#PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path" title="PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path"><code class="xref py py-meth docutils literal notranslate"><span class="pre">PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path()</span></code></a> generates a curve that passes through all waypoints.</p> +<p>This is a simple example of the interpolation planning:</p> +<img alt="../../../_images/interpolation1.png" src="../../../_images/interpolation1.png" /> +<p>This figure also shows curvatures of each path point using <a class="reference internal" href="../../utils/plot/plot.html#plot-curvature"><span class="std std-ref">utils.plot.plot_curvature</span></a>.</p> +<p>The default spline degree is 3, so curvature changes smoothly.</p> +<img alt="../../../_images/interp_and_curvature.png" src="../../../_images/interp_and_curvature.png" /> +<section id="api"> +<h3>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path"> +<span class="sig-prename descclassname"><span class="pre">PathPlanning.BSplinePath.bspline_path.</span></span><span class="sig-name descname"><span class="pre">interpolate_b_spline_path</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">y</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">n_path_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">degree</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">3</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">tuple</span></span></span><a class="reference internal" href="../../../_modules/PathPlanning/BSplinePath/bspline_path.html#interpolate_b_spline_path"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.BSplinePath.bspline_path.interpolate_b_spline_path" title="Permalink to this definition"></a></dt> +<dd><p>Interpolate x-y points with a B-Spline path</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>x</strong> (<em>array_like</em>) – x positions of interpolated points</p></li> +<li><p><strong>y</strong> (<em>array_like</em>) – y positions of interpolated points</p></li> +<li><p><strong>n_path_points</strong> (<em>int</em>) – number of path points</p></li> +<li><p><strong>degree</strong> (<em>int</em><em>, </em><em>optional</em>) – B-Spline degree. Must be 2<= k <= 5. Default: 3</p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><ul class="simple"> +<li><p><strong>x</strong> (<em>array</em>) – x positions of the result path</p></li> +<li><p><strong>y</strong> (<em>array</em>) – y positions of the result path</p></li> +<li><p><strong>heading</strong> (<em>array</em>) – heading of the result path</p></li> +<li><p><strong>curvature</strong> (<em>array</em>) – curvature of the result path</p></li> +</ul> +</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +<section id="bspline-approximation-planning"> +<h2>Bspline approximation planning<a class="headerlink" href="#bspline-approximation-planning" title="Permalink to this headline"></a></h2> +<p><a class="reference internal" href="#PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path" title="PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path"><code class="xref py py-meth docutils literal notranslate"><span class="pre">PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path()</span></code></a> +generates a curve that approximates the waypoints, which means that +the curve might not pass through waypoints.</p> +<p>Users can adjust path smoothness by the smoothing parameter <cite>s</cite>. If this +value is bigger, the path will be smoother, but it will be less accurate. +If this value is smaller, the path will be more accurate, but it will be +less smooth.</p> +<p>This is a simple example of the approximation planning:</p> +<img alt="../../../_images/approximation1.png" src="../../../_images/approximation1.png" /> +<p>This figure also shows curvatures of each path point using <a class="reference internal" href="../../utils/plot/plot.html#plot-curvature"><span class="std std-ref">utils.plot.plot_curvature</span></a>.</p> +<p>The default spline degree is 3, so curvature changes smoothly.</p> +<img alt="../../../_images/approx_and_curvature.png" src="../../../_images/approx_and_curvature.png" /> +<section id="id1"> +<h3>API<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3> +<dl class="py function"> +<dt class="sig sig-object py" id="PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path"> +<span class="sig-prename descclassname"><span class="pre">PathPlanning.BSplinePath.bspline_path.</span></span><span class="sig-name descname"><span class="pre">approximate_b_spline_path</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">y</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">n_path_points</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">degree</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">3</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">s</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">tuple</span></span></span><a class="reference internal" href="../../../_modules/PathPlanning/BSplinePath/bspline_path.html#approximate_b_spline_path"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.BSplinePath.bspline_path.approximate_b_spline_path" title="Permalink to this definition"></a></dt> +<dd><p>Approximate points with a B-Spline path</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>x</strong> (<em>array_like</em>) – x position list of approximated points</p></li> +<li><p><strong>y</strong> (<em>array_like</em>) – y position list of approximated points</p></li> +<li><p><strong>n_path_points</strong> (<em>int</em>) – number of path points</p></li> +<li><p><strong>degree</strong> (<em>int</em><em>, </em><em>optional</em>) – B Spline curve degree. Must be 2<= k <= 5. Default: 3.</p></li> +<li><p><strong>s</strong> (<em>int</em><em>, </em><em>optional</em>) – smoothing parameter. If this value is bigger, the path will be +smoother, but it will be less accurate. If this value is smaller, +the path will be more accurate, but it will be less smooth. +When <cite>s</cite> is 0, it is equivalent to the interpolation. Default is None, +in this case <cite>s</cite> will be <cite>len(x)</cite>.</p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><ul class="simple"> +<li><p><strong>x</strong> (<em>array</em>) – x positions of the result path</p></li> +<li><p><strong>y</strong> (<em>array</em>) – y positions of the result path</p></li> +<li><p><strong>heading</strong> (<em>array</em>) – heading of the result path</p></li> +<li><p><strong>curvature</strong> (<em>array</em>) – curvature of the result path</p></li> +</ul> +</p> +</dd> +</dl> +</dd></dl> + +</section> +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://en.wikipedia.org/wiki/B-spline">B-spline - Wikipedia</a></p></li> +<li><p><a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.UnivariateSpline.html">scipy.interpolate.UnivariateSpline</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../cubic_spline/cubic_spline.html" class="btn btn-neutral float-left" title="Cubic spline planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../clothoid_path/clothoid_path.html" class="btn btn-neutral float-right" title="Clothoid path planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/bugplanner/bugplanner.html b/modules/path_planning/bugplanner/bugplanner.html new file mode 100644 index 00000000000..46ef6f5bf5b --- /dev/null +++ b/modules/path_planning/bugplanner/bugplanner.html @@ -0,0 +1,170 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Bug planner — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Grid based search" href="../grid_base_search/grid_base_search.html" /> + <link rel="prev" title="Dynamic Window Approach" href="../dynamic_window_approach/dynamic_window_approach.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Bug planner</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/bugplanner/bugplanner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="bug-planner"> +<h1>Bug planner<a class="headerlink" href="#bug-planner" title="Permalink to this headline"></a></h1> +<p>This is a 2D planning with Bug algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BugPlanner/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BugPlanner/animation.gif" /> +<ul class="simple"> +<li><p><a class="reference external" href="https://sites.google.com/site/ece452bugalgorithms/">ECE452 Bug Algorithms</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../dynamic_window_approach/dynamic_window_approach.html" class="btn btn-neutral float-left" title="Dynamic Window Approach" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../grid_base_search/grid_base_search.html" class="btn btn-neutral float-right" title="Grid based search" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/clothoid_path/clothoid_path.html b/modules/path_planning/clothoid_path/clothoid_path.html new file mode 100644 index 00000000000..c68c084ac02 --- /dev/null +++ b/modules/path_planning/clothoid_path/clothoid_path.html @@ -0,0 +1,229 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Clothoid path planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Eta^3 Spline path planning" href="../eta3_spline/eta3_spline.html" /> + <link rel="prev" title="B-Spline planning" href="../bspline_path/bspline_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Clothoid path planning</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#step1-solve-g-function">Step1: Solve g function</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step2-calculate-path-parameters">Step2: Calculate path parameters</a></li> +<li class="toctree-l3"><a class="reference internal" href="#step3-construct-a-path-with-fresnel-integral">Step3: Construct a path with Fresnel integral</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Clothoid path planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/clothoid_path/clothoid_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="clothoid-path-planning"> +<span id="id1"></span><h1>Clothoid path planning<a class="headerlink" href="#clothoid-path-planning" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClothoidPath/animation1.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClothoidPath/animation1.gif" /> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClothoidPath/animation2.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClothoidPath/animation2.gif" /> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClothoidPath/animation3.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClothoidPath/animation3.gif" /> +<p>This is a clothoid path planning sample code.</p> +<p>This can interpolate two 2D pose (x, y, yaw) with a clothoid path, +which its curvature is linearly continuous. +In other words, this is G1 Hermite interpolation with a single clothoid segment.</p> +<p>This path planning algorithm as follows:</p> +<section id="step1-solve-g-function"> +<h2>Step1: Solve g function<a class="headerlink" href="#step1-solve-g-function" title="Permalink to this headline"></a></h2> +<p>Solve the g(A) function with a nonlinear optimization solver.</p> +<div class="math notranslate nohighlight"> +\[g(A):=Y(2A, \delta-A, \phi_{s})\]</div> +<p>Where</p> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(\delta\)</span>: the orientation difference between start and goal pose.</p></li> +<li><p><span class="math notranslate nohighlight">\(\phi_{s}\)</span>: the orientation of the start pose.</p></li> +<li><p><span class="math notranslate nohighlight">\(Y\)</span>: <span class="math notranslate nohighlight">\(Y(a, b, c)=\int_{0}^{1} \sin \left(\frac{a}{2} \tau^{2}+b \tau+c\right) d \tau\)</span></p></li> +</ul> +</section> +<section id="step2-calculate-path-parameters"> +<h2>Step2: Calculate path parameters<a class="headerlink" href="#step2-calculate-path-parameters" title="Permalink to this headline"></a></h2> +<p>We can calculate these path parameters using <span class="math notranslate nohighlight">\(A\)</span>,</p> +<p><span class="math notranslate nohighlight">\(L\)</span>: path length</p> +<div class="math notranslate nohighlight"> +\[L=\frac{R}{X\left(2 A, \delta-A, \phi_{s}\right)}\]</div> +<p>where</p> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(R\)</span>: the distance between start and goal pose</p></li> +<li><p><span class="math notranslate nohighlight">\(X\)</span>: <span class="math notranslate nohighlight">\(X(a, b, c)=\int_{0}^{1} \cos \left(\frac{a}{2} \tau^{2}+b \tau+c\right) d \tau\)</span></p></li> +</ul> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(\kappa\)</span>: curvature</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[\kappa=(\delta-A) / L\]</div> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(\kappa'\)</span>: curvature rate</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[\kappa^{\prime}=2 A / L^{2}\]</div> +</section> +<section id="step3-construct-a-path-with-fresnel-integral"> +<h2>Step3: Construct a path with Fresnel integral<a class="headerlink" href="#step3-construct-a-path-with-fresnel-integral" title="Permalink to this headline"></a></h2> +<p>The final clothoid path can be calculated with the path parameters and Fresnel integrals.</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} +&x(s)=x_{0}+\int_{0}^{s} \cos \left(\frac{1}{2} \kappa^{\prime} \tau^{2}+\kappa \tau+\vartheta_{0}\right) \mathrm{d} \tau \\ +&y(s)=y_{0}+\int_{0}^{s} \sin \left(\frac{1}{2} \kappa^{\prime} \tau^{2}+\kappa \tau+\vartheta_{0}\right) \mathrm{d} \tau +\end{aligned}\end{split}\]</div> +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.researchgate.net/publication/237062806">Fast and accurate G1 fitting of clothoid curves</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../bspline_path/bspline_path.html" class="btn btn-neutral float-left" title="B-Spline planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../eta3_spline/eta3_spline.html" class="btn btn-neutral float-right" title="Eta^3 Spline path planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/coverage_path/coverage_path.html b/modules/path_planning/coverage_path/coverage_path.html new file mode 100644 index 00000000000..e5e7f1640be --- /dev/null +++ b/modules/path_planning/coverage_path/coverage_path.html @@ -0,0 +1,195 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Coverage path planner — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Path Tracking" href="../../path_tracking/path_tracking.html" /> + <link rel="prev" title="Optimal Trajectory in a Frenet Frame" href="../frenet_frame_path/frenet_frame_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Coverage path planner</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#grid-based-sweep">Grid based sweep</a></li> +<li class="toctree-l3"><a class="reference internal" href="#spiral-spanning-tree">Spiral Spanning Tree</a></li> +<li class="toctree-l3"><a class="reference internal" href="#wavefront-path">Wavefront path</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Coverage path planner</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/coverage_path/coverage_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="coverage-path-planner"> +<h1>Coverage path planner<a class="headerlink" href="#coverage-path-planner" title="Permalink to this headline"></a></h1> +<section id="grid-based-sweep"> +<h2>Grid based sweep<a class="headerlink" href="#grid-based-sweep" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based sweep coverage path planner simulation:</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/GridBasedSweepCPP/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/GridBasedSweepCPP/animation.gif" /> +</section> +<section id="spiral-spanning-tree"> +<h2>Spiral Spanning Tree<a class="headerlink" href="#spiral-spanning-tree" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based spiral spanning tree coverage path planner simulation:</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/SpiralSpanningTreeCPP/animation1.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/SpiralSpanningTreeCPP/animation1.gif" /> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/SpiralSpanningTreeCPP/animation2.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/SpiralSpanningTreeCPP/animation2.gif" /> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/SpiralSpanningTreeCPP/animation3.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/SpiralSpanningTreeCPP/animation3.gif" /> +<ul class="simple"> +<li><p><a class="reference external" href="https://ieeexplore.ieee.org/abstract/document/1013479">Spiral-STC: An On-Line Coverage Algorithm of Grid Environments by a Mobile Robot</a></p></li> +</ul> +</section> +<section id="wavefront-path"> +<h2>Wavefront path<a class="headerlink" href="#wavefront-path" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based wavefront coverage path planner simulation:</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation1.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation1.gif" /> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation2.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation2.gif" /> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation3.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/WavefrontCPP/animation3.gif" /> +<ul class="simple"> +<li><p><a class="reference external" href="http://pinkwink.kr/attachment/cfile3.uf@1354654A4E8945BD13FE77.pdf">Planning paths of complete coverage of an unstructured environment by a mobile robot</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../frenet_frame_path/frenet_frame_path.html" class="btn btn-neutral float-left" title="Optimal Trajectory in a Frenet Frame" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../path_tracking/path_tracking.html" class="btn btn-neutral float-right" title="Path Tracking" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/cubic_spline/cubic_spline.html b/modules/path_planning/cubic_spline/cubic_spline.html new file mode 100644 index 00000000000..7a7035d7247 --- /dev/null +++ b/modules/path_planning/cubic_spline/cubic_spline.html @@ -0,0 +1,524 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Cubic spline planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="B-Spline planning" href="../bspline_path/bspline_path.html" /> + <link rel="prev" title="Rapidly-Exploring Random Trees (RRT)" href="../rrt/rrt.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Cubic spline planning</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#spline-curve-continuity">Spline curve continuity</a></li> +<li class="toctree-l3"><a class="reference internal" href="#d-cubic-spline">1D cubic spline</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#constraint-1-terminal-constraints">Constraint 1: Terminal constraints</a></li> +<li class="toctree-l4"><a class="reference internal" href="#constraint-2-point-continuous-constraints">Constraint 2: Point continuous constraints</a></li> +<li class="toctree-l4"><a class="reference internal" href="#constraint-3-tangent-vector-continuous-constraints">Constraint 3: Tangent vector continuous constraints</a></li> +<li class="toctree-l4"><a class="reference internal" href="#constraint-4-curvature-continuous-constraints">Constraint 4: Curvature continuous constraints</a></li> +<li class="toctree-l4"><a class="reference internal" href="#constraint-5-terminal-curvature-constraints">Constraint 5: Terminal curvature constraints</a></li> +<li class="toctree-l4"><a class="reference internal" href="#how-to-calculate-the-unknown-parameters-a-j-b-j-c-j-d-j">How to calculate the unknown parameters <span class="math notranslate nohighlight">\(a_j, b_j, c_j, d_j\)</span></a></li> +<li class="toctree-l4"><a class="reference internal" href="#how-to-calculate-the-first-and-second-derivatives-of-the-spline-curve">How to calculate the first and second derivatives of the spline curve</a></li> +<li class="toctree-l4"><a class="reference internal" href="#api">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#id1">2D cubic spline</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#id2">API</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Cubic spline planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/cubic_spline/cubic_spline_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="cubic-spline-planning"> +<h1>Cubic spline planning<a class="headerlink" href="#cubic-spline-planning" title="Permalink to this headline"></a></h1> +<section id="spline-curve-continuity"> +<h2>Spline curve continuity<a class="headerlink" href="#spline-curve-continuity" title="Permalink to this headline"></a></h2> +<p>Spline curve smoothness is depending on the which kind of spline model is used.</p> +<p>The smoothness of the spline curve is expressed as <span class="math notranslate nohighlight">\(C_0, C_1\)</span>, and so on.</p> +<p>This representation represents continuity of the curve. +For example, for a spline curve in two-dimensional space:</p> +<ul class="simple"> +<li><p><span class="math notranslate nohighlight">\(C_0\)</span> is position continuous</p></li> +<li><p><span class="math notranslate nohighlight">\(C_1\)</span> is tangent vector continuous</p></li> +<li><p><span class="math notranslate nohighlight">\(C_2\)</span> is curvature vector continuous</p></li> +</ul> +<p>as shown in the following figure:</p> +<img alt="../../../_images/spline_continuity.png" src="../../../_images/spline_continuity.png" /> +<p>Cubic spline can generate a curve with <span class="math notranslate nohighlight">\(C_0, C_1, C_2\)</span>.</p> +</section> +<section id="d-cubic-spline"> +<h2>1D cubic spline<a class="headerlink" href="#d-cubic-spline" title="Permalink to this headline"></a></h2> +<p>Cubic spline interpolation is a method of smoothly +interpolating between multiple data points when given +multiple data points, as shown in the figure below.</p> +<img alt="../../../_images/spline.png" src="../../../_images/spline.png" /> +<p>It separates between each interval between data points.</p> +<p>The each interval part is approximated by each cubic polynomial.</p> +<p>The cubic spline uses the cubic polynomial equation for interpolation:</p> +<p><span class="math notranslate nohighlight">\(S_j(x)=a_j+b_j(x-x_j)+c_j(x-x_j)^2+d_j(x-x_j)^3\)</span></p> +<p>where <span class="math notranslate nohighlight">\(x_j < x < x_{j+1}\)</span>, <span class="math notranslate nohighlight">\(x_j\)</span> is the j-th node of the spline, +<span class="math notranslate nohighlight">\(a_j\)</span>, <span class="math notranslate nohighlight">\(b_j\)</span>, <span class="math notranslate nohighlight">\(c_j\)</span>, <span class="math notranslate nohighlight">\(d_j\)</span> are the coefficients +of the spline.</p> +<p>As the above equation, there are 4 unknown parameters <span class="math notranslate nohighlight">\((a,b,c,d)\)</span> for +one interval, so if the number of data points is <span class="math notranslate nohighlight">\(N\)</span>, the +interpolation has <span class="math notranslate nohighlight">\(4N\)</span> unknown parameters.</p> +<p>The following five conditions are used to determine the <span class="math notranslate nohighlight">\(4N\)</span> +unknown parameters:</p> +<section id="constraint-1-terminal-constraints"> +<h3>Constraint 1: Terminal constraints<a class="headerlink" href="#constraint-1-terminal-constraints" title="Permalink to this headline"></a></h3> +<p><span class="math notranslate nohighlight">\(S_j(x_j)=y_j\)</span></p> +<p>This constraint is the terminal constraint of each interval.</p> +<p>The polynomial of each interval will pass through the x,y coordinates of +the data points.</p> +</section> +<section id="constraint-2-point-continuous-constraints"> +<h3>Constraint 2: Point continuous constraints<a class="headerlink" href="#constraint-2-point-continuous-constraints" title="Permalink to this headline"></a></h3> +<p><span class="math notranslate nohighlight">\(S_j(x_{j+1})=S_{j+1}(x_{j+1})=y_{j+1}\)</span></p> +<p>This constraint is a continuity condition for the boundary of each interval.</p> +<p>This constraint ensures that the boundary of each interval is continuous.</p> +</section> +<section id="constraint-3-tangent-vector-continuous-constraints"> +<h3>Constraint 3: Tangent vector continuous constraints<a class="headerlink" href="#constraint-3-tangent-vector-continuous-constraints" title="Permalink to this headline"></a></h3> +<p><span class="math notranslate nohighlight">\(S'_j(x_{j+1})=S'_{j+1}(x_{j+1})\)</span></p> +<p>This constraint is a continuity condition for the first derivative of +the boundary of each interval.</p> +<p>This constraint makes the vectors of the boundaries of each +interval continuous.</p> +</section> +<section id="constraint-4-curvature-continuous-constraints"> +<h3>Constraint 4: Curvature continuous constraints<a class="headerlink" href="#constraint-4-curvature-continuous-constraints" title="Permalink to this headline"></a></h3> +<p><span class="math notranslate nohighlight">\(S''_j(x_{j+1})=S''_{j+1}(x_{j+1})\)</span></p> +<p>This constraint is the continuity condition for the second derivative of +the boundary of each interval.</p> +<p>This constraint makes the curvature of the boundaries of each +interval continuous.</p> +</section> +<section id="constraint-5-terminal-curvature-constraints"> +<h3>Constraint 5: Terminal curvature constraints<a class="headerlink" href="#constraint-5-terminal-curvature-constraints" title="Permalink to this headline"></a></h3> +<p><span class="math notranslate nohighlight">\(S''_0(0)=S''_{n+1}(x_{n})=0\)</span>.</p> +<p>The constraint is a boundary condition for the second derivative of the starting and ending points.</p> +<p>Our sample code assumes these terminal curvatures are 0, which is well known as Natural Cubic Spline.</p> +</section> +<section id="how-to-calculate-the-unknown-parameters-a-j-b-j-c-j-d-j"> +<h3>How to calculate the unknown parameters <span class="math notranslate nohighlight">\(a_j, b_j, c_j, d_j\)</span><a class="headerlink" href="#how-to-calculate-the-unknown-parameters-a-j-b-j-c-j-d-j" title="Permalink to this headline"></a></h3> +<section id="step1-calculate-a-j"> +<h4>Step1: calculate <span class="math notranslate nohighlight">\(a_j\)</span><a class="headerlink" href="#step1-calculate-a-j" title="Permalink to this headline"></a></h4> +<p>Spline coefficients <span class="math notranslate nohighlight">\(a_j\)</span> can be calculated by y positions of the data points:</p> +<p><span class="math notranslate nohighlight">\(a_j = y_i\)</span>.</p> +</section> +<section id="step2-calculate-c-j"> +<h4>Step2: calculate <span class="math notranslate nohighlight">\(c_j\)</span><a class="headerlink" href="#step2-calculate-c-j" title="Permalink to this headline"></a></h4> +<p>Spline coefficients <span class="math notranslate nohighlight">\(c_j\)</span> can be calculated by solving the linear equation:</p> +<p><span class="math notranslate nohighlight">\(Ac_j = B\)</span>.</p> +<p>The matrix <span class="math notranslate nohighlight">\(A\)</span> and <span class="math notranslate nohighlight">\(B\)</span> are defined as follows:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}A=\left[\begin{array}{cccccc} +1 & 0 & 0 & 0 & \cdots & 0 \\ +h_{0} & 2\left(h_{0}+h_{1}\right) & h_{1} & 0 & \cdots & 0 \\ +0 & h_{1} & 2\left(h_{1}+h_{2}\right) & h_{2} & \cdots & 0 \\ +0 & 0 & h_{2} & 2\left(h_{2}+h_{3}\right) & \cdots & 0 \\ +0 & 0 & 0 & h_{3} & \ddots & \\ +\vdots & \vdots & & & & \\ +0 & 0 & 0 & \cdots & 0 & 1 +\end{array}\right]\end{split}\]</div> +<div class="math notranslate nohighlight"> +\[\begin{split}B=\left[\begin{array}{c} +0 \\ +\frac{3}{h_{1}}\left(a_{2}-a_{1}\right)-\frac{3}{h_{0}}\left(a_{1}-a_{0}\right) \\ +\vdots \\ +\frac{3}{h_{n-1}}\left(a_{n}-a_{n-1}\right)-\frac{3}{h_{n-2}}\left(a_{n-1}-a_{n-2}\right) \\ +0 +\end{array}\right]\end{split}\]</div> +<p>where <span class="math notranslate nohighlight">\(h_{i}\)</span> is the x position distance between the i-th and (i+1)-th data points.</p> +</section> +<section id="step3-calculate-d-j"> +<h4>Step3: calculate <span class="math notranslate nohighlight">\(d_j\)</span><a class="headerlink" href="#step3-calculate-d-j" title="Permalink to this headline"></a></h4> +<p>Spline coefficients <span class="math notranslate nohighlight">\(d_j\)</span> can be calculated by the following equation:</p> +<p><span class="math notranslate nohighlight">\(d_{j}=\frac{c_{j+1}-c_{j}}{3 h_{j}}\)</span></p> +</section> +<section id="step4-calculate-b-j"> +<h4>Step4: calculate <span class="math notranslate nohighlight">\(b_j\)</span><a class="headerlink" href="#step4-calculate-b-j" title="Permalink to this headline"></a></h4> +<p>Spline coefficients <span class="math notranslate nohighlight">\(b_j\)</span> can be calculated by the following equation:</p> +<p><span class="math notranslate nohighlight">\(b_{i}=\frac{1}{h_i}(a_{i+1}-a_{i})-\frac{h_i}{3}(2c_{i}+c_{i+1})\)</span></p> +</section> +</section> +<section id="how-to-calculate-the-first-and-second-derivatives-of-the-spline-curve"> +<h3>How to calculate the first and second derivatives of the spline curve<a class="headerlink" href="#how-to-calculate-the-first-and-second-derivatives-of-the-spline-curve" title="Permalink to this headline"></a></h3> +<p>After we can get the coefficients of the spline curve, we can calculate</p> +<p>the first derivative by:</p> +<p><span class="math notranslate nohighlight">\(y^{\prime}(x)=b+2cx+3dx^2\)</span></p> +<p>the second derivative by:</p> +<p><span class="math notranslate nohighlight">\(y^{\prime \prime}(x)=2c+6dx\)</span></p> +<p>These equations can be calculated by differentiating the cubic polynomial.</p> +</section> +<section id="api"> +<h3>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h3> +<p>This is the 1D cubic spline class API:</p> +<dl class="py class"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D"> +<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">PathPlanning.CubicSpline.cubic_spline_planner.</span></span><span class="sig-name descname"><span class="pre">CubicSpline1D</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">y</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline1D"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D" title="Permalink to this definition"></a></dt> +<dd><p>1D Cubic Spline class</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>x</strong> (<em>list</em>) – x coordinates for data points. This x coordinates must be +sorted +in ascending order.</p></li> +<li><p><strong>y</strong> (<em>list</em>) – y coordinates for data points</p></li> +</ul> +</dd> +</dl> +<p class="rubric">Examples</p> +<p>You can interpolate 1D data points.</p> +<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="gp">>>> </span><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="gp">>>> </span><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.7</span><span class="p">,</span> <span class="o">-</span><span class="mi">6</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]</span> +<span class="gp">>>> </span><span class="n">sp</span> <span class="o">=</span> <span class="n">CubicSpline1D</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">xi</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">yi</span> <span class="o">=</span> <span class="p">[</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">xi</span><span class="p">]</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"xb"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Data points"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xi</span><span class="p">,</span> <span class="n">yi</span> <span class="p">,</span> <span class="s2">"r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Cubic spline interpolation"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/cubic_spline_1d.png" src="../../../_images/cubic_spline_1d.png" /> +<dl class="py method"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_first_derivative"> +<span class="sig-name descname"><span class="pre">calc_first_derivative</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline1D.calc_first_derivative"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_first_derivative" title="Permalink to this definition"></a></dt> +<dd><p>Calc first derivative at given x.</p> +<p>if x is outside the input x, return None</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><strong>dy</strong> – first derivative for given x.</p> +</dd> +<dt class="field-even">Return type</dt> +<dd class="field-even"><p>float</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_position"> +<span class="sig-name descname"><span class="pre">calc_position</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline1D.calc_position"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_position" title="Permalink to this definition"></a></dt> +<dd><p>Calc <cite>y</cite> position for given <cite>x</cite>.</p> +<p>if <cite>x</cite> is outside the data point’s <cite>x</cite> range, return None.</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><strong>y</strong> – y position for given x.</p> +</dd> +<dt class="field-even">Return type</dt> +<dd class="field-even"><p>float</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_second_derivative"> +<span class="sig-name descname"><span class="pre">calc_second_derivative</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline1D.calc_second_derivative"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D.calc_second_derivative" title="Permalink to this definition"></a></dt> +<dd><p>Calc second derivative at given x.</p> +<p>if x is outside the input x, return None</p> +<dl class="field-list simple"> +<dt class="field-odd">Returns</dt> +<dd class="field-odd"><p><strong>ddy</strong> – second derivative for given x.</p> +</dd> +<dt class="field-even">Return type</dt> +<dd class="field-even"><p>float</p> +</dd> +</dl> +</dd></dl> + +</dd></dl> + +</section> +</section> +<section id="id1"> +<h2>2D cubic spline<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h2> +<p>Data x positions needs to be mono-increasing for 1D cubic spline.</p> +<p>So, it cannot be used for 2D path planning.</p> +<p>2D cubic spline uses two 1D cubic splines based on path distance from +the start point for each dimension x and y.</p> +<p>This can generate a curvature continuous path based on x-y waypoints.</p> +<p>Heading angle of each point can be calculated analytically by:</p> +<p><span class="math notranslate nohighlight">\(\theta=\tan ^{-1} \frac{y’}{x’}\)</span></p> +<p>Curvature of each point can be also calculated analytically by:</p> +<p><span class="math notranslate nohighlight">\(\kappa=\frac{y^{\prime \prime} x^{\prime}-x^{\prime \prime} y^{\prime}}{\left(x^{\prime2}+y^{\prime2}\right)^{\frac{2}{3}}}\)</span></p> +<section id="id2"> +<h3>API<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3> +<dl class="py class"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D"> +<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">PathPlanning.CubicSpline.cubic_spline_planner.</span></span><span class="sig-name descname"><span class="pre">CubicSpline2D</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">y</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline2D"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D" title="Permalink to this definition"></a></dt> +<dd><p>Cubic CubicSpline2D class</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>x</strong> (<em>list</em>) – x coordinates for data points.</p></li> +<li><p><strong>y</strong> (<em>list</em>) – y coordinates for data points.</p></li> +</ul> +</dd> +</dl> +<p class="rubric">Examples</p> +<p>You can interpolate a 2D data points.</p> +<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="gp">>>> </span><span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">2.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="mf">7.5</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">]</span> +<span class="gp">>>> </span><span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.7</span><span class="p">,</span> <span class="o">-</span><span class="mi">6</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">]</span> +<span class="gp">>>> </span><span class="n">ds</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="c1"># [m] distance of each interpolated points</span> +<span class="gp">>>> </span><span class="n">sp</span> <span class="o">=</span> <span class="n">CubicSpline2D</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">s</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sp</span><span class="o">.</span><span class="n">s</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">ds</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">rx</span><span class="p">,</span> <span class="n">ry</span><span class="p">,</span> <span class="n">ryaw</span><span class="p">,</span> <span class="n">rk</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span> +<span class="gp">>>> </span><span class="k">for</span> <span class="n">i_s</span> <span class="ow">in</span> <span class="n">s</span><span class="p">:</span> +<span class="gp">... </span> <span class="n">ix</span><span class="p">,</span> <span class="n">iy</span> <span class="o">=</span> <span class="n">sp</span><span class="o">.</span><span class="n">calc_position</span><span class="p">(</span><span class="n">i_s</span><span class="p">)</span> +<span class="gp">... </span> <span class="n">rx</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ix</span><span class="p">)</span> +<span class="gp">... </span> <span class="n">ry</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">iy</span><span class="p">)</span> +<span class="gp">... </span> <span class="n">ryaw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_yaw</span><span class="p">(</span><span class="n">i_s</span><span class="p">))</span> +<span class="gp">... </span> <span class="n">rk</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sp</span><span class="o">.</span><span class="n">calc_curvature</span><span class="p">(</span><span class="n">i_s</span><span class="p">))</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"xb"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Data points"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">rx</span><span class="p">,</span> <span class="n">ry</span><span class="p">,</span> <span class="s2">"-r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Cubic spline path"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"x[m]"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"y[m]"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/cubic_spline_2d_path.png" src="../../../_images/cubic_spline_2d_path.png" /> +<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">rad2deg</span><span class="p">(</span><span class="n">iyaw</span><span class="p">)</span> <span class="k">for</span> <span class="n">iyaw</span> <span class="ow">in</span> <span class="n">ryaw</span><span class="p">],</span> <span class="s2">"-r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"yaw"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"line length[m]"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"yaw angle[deg]"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/cubic_spline_2d_yaw.png" src="../../../_images/cubic_spline_2d_yaw.png" /> +<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">rk</span><span class="p">,</span> <span class="s2">"-r"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"curvature"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"line length[m]"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"curvature [1/m]"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/cubic_spline_2d_curvature.png" src="../../../_images/cubic_spline_2d_curvature.png" /> +<dl class="py method"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_curvature"> +<span class="sig-name descname"><span class="pre">calc_curvature</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">s</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline2D.calc_curvature"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_curvature" title="Permalink to this definition"></a></dt> +<dd><p>calc curvature</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><p><strong>s</strong> (<em>float</em>) – distance from the start point. if <cite>s</cite> is outside the data point’s +range, return None.</p> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><strong>k</strong> – curvature for given s.</p> +</dd> +<dt class="field-odd">Return type</dt> +<dd class="field-odd"><p>float</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_position"> +<span class="sig-name descname"><span class="pre">calc_position</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">s</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline2D.calc_position"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_position" title="Permalink to this definition"></a></dt> +<dd><p>calc position</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><p><strong>s</strong> (<em>float</em>) – distance from the start point. if <cite>s</cite> is outside the data point’s +range, return None.</p> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><ul class="simple"> +<li><p><strong>x</strong> (<em>float</em>) – x position for given s.</p></li> +<li><p><strong>y</strong> (<em>float</em>) – y position for given s.</p></li> +</ul> +</p> +</dd> +</dl> +</dd></dl> + +<dl class="py method"> +<dt class="sig sig-object py" id="PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_yaw"> +<span class="sig-name descname"><span class="pre">calc_yaw</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">s</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/CubicSpline/cubic_spline_planner.html#CubicSpline2D.calc_yaw"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D.calc_yaw" title="Permalink to this definition"></a></dt> +<dd><p>calc yaw</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><p><strong>s</strong> (<em>float</em>) – distance from the start point. if <cite>s</cite> is outside the data point’s +range, return None.</p> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><strong>yaw</strong> – yaw angle (tangent vector) for given s.</p> +</dd> +<dt class="field-odd">Return type</dt> +<dd class="field-odd"><p>float</p> +</dd> +</dl> +</dd></dl> + +</dd></dl> + +</section> +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://people.clas.ufl.edu/kees/files/CubicSplines.pdf">Cubic Splines James Keesling</a></p></li> +<li><p><a class="reference external" href="http://www.cs.cmu.edu/afs/cs/academic/class/15462-s10/www/lec-slides/lec06.pdf">Curves and Splines</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../rrt/rrt.html" class="btn btn-neutral float-left" title="Rapidly-Exploring Random Trees (RRT)" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../bspline_path/bspline_path.html" class="btn btn-neutral float-right" title="B-Spline planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/dubins_path/dubins_path.html b/modules/path_planning/dubins_path/dubins_path.html new file mode 100644 index 00000000000..e4c16f25ceb --- /dev/null +++ b/modules/path_planning/dubins_path/dubins_path.html @@ -0,0 +1,270 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Dubins path planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Reeds Shepp planning" href="../reeds_shepp_path/reeds_shepp_path.html" /> + <link rel="prev" title="Quintic polynomials planning" href="../quintic_polynomials_planner/quintic_polynomials_planner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Dubins path planning</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#dubins-path">Dubins path</a></li> +<li class="toctree-l3"><a class="reference internal" href="#api">API</a></li> +<li class="toctree-l3"><a class="reference internal" href="#reference">Reference</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Dubins path planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/dubins_path/dubins_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="dubins-path-planning"> +<h1>Dubins path planning<a class="headerlink" href="#dubins-path-planning" title="Permalink to this headline"></a></h1> +<p>A sample code for Dubins path planning.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DubinsPath/animation.gif?raw=True" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DubinsPath/animation.gif?raw=True" /> +<section id="dubins-path"> +<h2>Dubins path<a class="headerlink" href="#dubins-path" title="Permalink to this headline"></a></h2> +<p>Dubins path is a analytical path planning algorithm for a simple car model.</p> +<p>It can generates a shortest path between two 2D poses (x, y, yaw) with maximum curvature constraint and tangent(yaw angle) constraint.</p> +<p>Generated paths consist of 3 segments of maximum curvature curves or a straight line segment.</p> +<p>Each segment type can is categorized by 3 type: ‘Right turn (R)’ , ‘Left turn (L)’, and ‘Straight (S).’</p> +<p>Possible path will be at least one of these six types: RSR, RSL, LSR, LSL, RLR, LRL.</p> +<p>Dubins path planner can output each segment type and distance of each course segment.</p> +<p>For example, a RSR Dubins path is:</p> +<a class="reference internal image-reference" href="../../../_images/RSR.jpg"><img alt="../../../_images/RSR.jpg" src="../../../_images/RSR.jpg" style="width: 400px;" /></a> +<p>Each segment distance can be calculated by:</p> +<p><span class="math notranslate nohighlight">\(\alpha = mod(-\theta)\)</span></p> +<p><span class="math notranslate nohighlight">\(\beta = mod(x_{e, yaw} - \theta)\)</span></p> +<p><span class="math notranslate nohighlight">\(p^2 = 2 + d ^ 2 - 2\cos(\alpha-\beta) + 2d(\sin\alpha - \sin\beta)\)</span></p> +<p><span class="math notranslate nohighlight">\(t = atan2(\cos\beta - \cos\alpha, d + \sin\alpha - \sin\beta)\)</span></p> +<p><span class="math notranslate nohighlight">\(d_1 = mod(-\alpha + t)\)</span></p> +<p><span class="math notranslate nohighlight">\(d_2 = p\)</span></p> +<p><span class="math notranslate nohighlight">\(d_3 = mod(\beta - t)\)</span></p> +<p>where <span class="math notranslate nohighlight">\(\theta\)</span> is tangent and d is distance from <span class="math notranslate nohighlight">\(x_s\)</span> to <span class="math notranslate nohighlight">\(x_e\)</span></p> +<p>A RLR Dubins path is:</p> +<a class="reference internal image-reference" href="../../../_images/RLR.jpg"><img alt="../../../_images/RLR.jpg" src="../../../_images/RLR.jpg" style="width: 200px;" /></a> +<p>Each segment distance can be calculated by:</p> +<p><span class="math notranslate nohighlight">\(t = (6.0 - d^2 + 2\cos(\alpha-\beta) + 2d(\sin\alpha - \sin\beta)) / 8.0\)</span></p> +<p><span class="math notranslate nohighlight">\(d_2 = mod(2\pi - acos(t))\)</span></p> +<p><span class="math notranslate nohighlight">\(d_1 = mod(\alpha - atan2(\cos\beta - \cos\alpha, d + \sin\alpha - \sin\beta) + d_2 / 2.0)\)</span></p> +<p><span class="math notranslate nohighlight">\(d_3 = mod(\alpha - \beta - d_1 + d_2)\)</span></p> +<p>You can generate a path from these information and the maximum curvature information.</p> +<p>A path type which has minimum course length among 6 types is selected, +and then a path is constructed based on the selected type and its distances.</p> +</section> +<section id="api"> +<h2>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h2> +<dl class="py function"> +<dt class="sig sig-object py" id="PathPlanning.DubinsPath.dubins_path_planner.plan_dubins_path"> +<span class="sig-prename descclassname"><span class="pre">PathPlanning.DubinsPath.dubins_path_planner.</span></span><span class="sig-name descname"><span class="pre">plan_dubins_path</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">s_x</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">s_y</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">s_yaw</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">g_x</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">g_y</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">g_yaw</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">curvature</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">step_size</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0.1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">selected_types</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/PathPlanning/DubinsPath/dubins_path_planner.html#plan_dubins_path"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#PathPlanning.DubinsPath.dubins_path_planner.plan_dubins_path" title="Permalink to this definition"></a></dt> +<dd><p>Plan dubins path</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>s_x</strong> (<em>float</em>) – x position of the start point [m]</p></li> +<li><p><strong>s_y</strong> (<em>float</em>) – y position of the start point [m]</p></li> +<li><p><strong>s_yaw</strong> (<em>float</em>) – yaw angle of the start point [rad]</p></li> +<li><p><strong>g_x</strong> (<em>float</em>) – x position of the goal point [m]</p></li> +<li><p><strong>g_y</strong> (<em>float</em>) – y position of the end point [m]</p></li> +<li><p><strong>g_yaw</strong> (<em>float</em>) – yaw angle of the end point [rad]</p></li> +<li><p><strong>curvature</strong> (<em>float</em>) – curvature for curve [1/m]</p></li> +<li><p><strong>step_size</strong> (<em>float</em><em> (</em><em>optional</em><em>)</em>) – step size between two path points [m]. Default is 0.1</p></li> +<li><p><strong>selected_types</strong> (<em>a list of string</em><em> or </em><em>None</em>) – selected path planning types. If None, all types are used for +path planning, and minimum path length result is returned. +You can select used path plannings types by a string list. +e.g.: [“RSL”, “RSR”]</p></li> +</ul> +</dd> +<dt class="field-even">Returns</dt> +<dd class="field-even"><p><ul class="simple"> +<li><p><strong>x_list</strong> (<em>array</em>) – x positions of the path</p></li> +<li><p><strong>y_list</strong> (<em>array</em>) – y positions of the path</p></li> +<li><p><strong>yaw_list</strong> (<em>array</em>) – yaw angles of the path</p></li> +<li><p><strong>modes</strong> (<em>array</em>) – mode list of the path</p></li> +<li><p><strong>lengths</strong> (<em>array</em>) – arrow_length list of the path segments.</p></li> +</ul> +</p> +</dd> +</dl> +<p class="rubric">Examples</p> +<p>You can generate a dubins path.</p> +<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">start_x</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1"># [m]</span> +<span class="gp">>>> </span><span class="n">start_y</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1"># [m]</span> +<span class="gp">>>> </span><span class="n">start_yaw</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">45.0</span><span class="p">)</span> <span class="c1"># [rad]</span> +<span class="gp">>>> </span><span class="n">end_x</span> <span class="o">=</span> <span class="o">-</span><span class="mf">3.0</span> <span class="c1"># [m]</span> +<span class="gp">>>> </span><span class="n">end_y</span> <span class="o">=</span> <span class="o">-</span><span class="mf">3.0</span> <span class="c1"># [m]</span> +<span class="gp">>>> </span><span class="n">end_yaw</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="o">-</span><span class="mf">45.0</span><span class="p">)</span> <span class="c1"># [rad]</span> +<span class="gp">>>> </span><span class="n">curvature</span> <span class="o">=</span> <span class="mf">1.0</span> +<span class="gp">>>> </span><span class="n">path_x</span><span class="p">,</span> <span class="n">path_y</span><span class="p">,</span> <span class="n">path_yaw</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">plan_dubins_path</span><span class="p">(</span> +<span class="go"> start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">path_x</span><span class="p">,</span> <span class="n">path_y</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"final course "</span> <span class="o">+</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">mode</span><span class="p">))</span> +<span class="gp">>>> </span><span class="n">plot_arrow</span><span class="p">(</span><span class="n">start_x</span><span class="p">,</span> <span class="n">start_y</span><span class="p">,</span> <span class="n">start_yaw</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plot_arrow</span><span class="p">(</span><span class="n">end_x</span><span class="p">,</span> <span class="n">end_y</span><span class="p">,</span> <span class="n">end_yaw</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/dubins_path.jpg" src="../../../_images/dubins_path.jpg" /> +</dd></dl> + +</section> +<section id="reference"> +<h2>Reference<a class="headerlink" href="#reference" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.jstor.org/stable/2372560?origin=crossref">On Curves of Minimal Length with a Constraint on Average Curvature, and with Prescribed Initial and Terminal Positions and Tangents</a></p></li> +<li><p><a class="reference external" href="https://en.wikipedia.org/wiki/Dubins_path">Dubins path - Wikipedia</a></p></li> +<li><p><a class="reference external" href="http://planning.cs.uiuc.edu/node821.html">15.3.1 Dubins Curves</a></p></li> +<li><p><a class="reference external" href="https://gieseanw.wordpress.com/2012/10/21/a-comprehensive-step-by-step-tutorial-to-computing-dubins-paths/">A Comprehensive, Step-by-Step Tutorial to Computing Dubin’s Paths</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../quintic_polynomials_planner/quintic_polynomials_planner.html" class="btn btn-neutral float-left" title="Quintic polynomials planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../reeds_shepp_path/reeds_shepp_path.html" class="btn btn-neutral float-right" title="Reeds Shepp planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/dynamic_window_approach/dynamic_window_approach.html b/modules/path_planning/dynamic_window_approach/dynamic_window_approach.html new file mode 100644 index 00000000000..72f37ad7052 --- /dev/null +++ b/modules/path_planning/dynamic_window_approach/dynamic_window_approach.html @@ -0,0 +1,171 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Dynamic Window Approach — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Bug planner" href="../bugplanner/bugplanner.html" /> + <link rel="prev" title="Path Planning" href="../path_planning.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Dynamic Window Approach</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/dynamic_window_approach/dynamic_window_approach_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="dynamic-window-approach"> +<span id="id1"></span><h1>Dynamic Window Approach<a class="headerlink" href="#dynamic-window-approach" title="Permalink to this headline"></a></h1> +<p>This is a 2D navigation sample code with Dynamic Window Approach.</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.ri.cmu.edu/pub_files/pub1/fox_dieter_1997_1/fox_dieter_1997_1.pdf">The Dynamic Window Approach to Collision +Avoidance</a></p></li> +</ul> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DynamicWindowApproach/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DynamicWindowApproach/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../path_planning.html" class="btn btn-neutral float-left" title="Path Planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../bugplanner/bugplanner.html" class="btn btn-neutral float-right" title="Bug planner" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/eta3_spline/eta3_spline.html b/modules/path_planning/eta3_spline/eta3_spline.html new file mode 100644 index 00000000000..98af3a87509 --- /dev/null +++ b/modules/path_planning/eta3_spline/eta3_spline.html @@ -0,0 +1,172 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Eta^3 Spline path planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Bezier path planning" href="../bezier_path/bezier_path.html" /> + <link rel="prev" title="Clothoid path planning" href="../clothoid_path/clothoid_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Eta^3 Spline path planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/eta3_spline/eta3_spline_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="eta-3-spline-path-planning"> +<span id="id1"></span><h1>Eta^3 Spline path planning<a class="headerlink" href="#eta-3-spline-path-planning" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/Eta3SplinePath/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/Eta3SplinePath/animation.gif" /> +<p>This is a path planning with Eta^3 spline.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://ieeexplore.ieee.org/document/4339545/">\eta^3-Splines for the Smooth Path Generation of Wheeled Mobile +Robots</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../clothoid_path/clothoid_path.html" class="btn btn-neutral float-left" title="Clothoid path planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../bezier_path/bezier_path.html" class="btn btn-neutral float-right" title="Bezier path planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/frenet_frame_path/frenet_frame_path.html b/modules/path_planning/frenet_frame_path/frenet_frame_path.html new file mode 100644 index 00000000000..38f0137762c --- /dev/null +++ b/modules/path_planning/frenet_frame_path/frenet_frame_path.html @@ -0,0 +1,177 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Optimal Trajectory in a Frenet Frame — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Coverage path planner" href="../coverage_path/coverage_path.html" /> + <link rel="prev" title="Hybrid a star" href="../hybridastar/hybridastar.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Optimal Trajectory in a Frenet Frame</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/frenet_frame_path/frenet_frame_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="optimal-trajectory-in-a-frenet-frame"> +<h1>Optimal Trajectory in a Frenet Frame<a class="headerlink" href="#optimal-trajectory-in-a-frenet-frame" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/FrenetOptimalTrajectory/animation.gif" /> +<p>This is optimal trajectory generation in a Frenet Frame.</p> +<p>The cyan line is the target course and black crosses are obstacles.</p> +<p>The red line is predicted path.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.researchgate.net/profile/Moritz_Werling/publication/224156269_Optimal_Trajectory_Generation_for_Dynamic_Street_Scenarios_in_a_Frenet_Frame/links/54f749df0cf210398e9277af.pdf">Optimal Trajectory Generation for Dynamic Street Scenarios in a +Frenet +Frame</a></p></li> +<li><p><a class="reference external" href="https://www.youtube.com/watch?v=Cj6tAQe7UCY">Optimal trajectory generation for dynamic street scenarios in a +Frenet Frame</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../hybridastar/hybridastar.html" class="btn btn-neutral float-left" title="Hybrid a star" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../coverage_path/coverage_path.html" class="btn btn-neutral float-right" title="Coverage path planner" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/grid_base_search/grid_base_search.html b/modules/path_planning/grid_base_search/grid_base_search.html new file mode 100644 index 00000000000..bb97eec86f5 --- /dev/null +++ b/modules/path_planning/grid_base_search/grid_base_search.html @@ -0,0 +1,236 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Grid based search — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Model Predictive Trajectory Generator" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html" /> + <link rel="prev" title="Bug planner" href="../bugplanner/bugplanner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Grid based search</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#breadth-first-search">Breadth First Search</a></li> +<li class="toctree-l3"><a class="reference internal" href="#depth-first-search">Depth First Search</a></li> +<li class="toctree-l3"><a class="reference internal" href="#dijkstra-algorithm">Dijkstra algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#a-algorithm">A* algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#bidirectional-a-algorithm">Bidirectional A* algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#d-algorithm">D* algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#d-lite-algorithm">D* lite algorithm</a></li> +<li class="toctree-l3"><a class="reference internal" href="#potential-field-algorithm">Potential Field algorithm</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Grid based search</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/grid_base_search/grid_base_search_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="grid-based-search"> +<h1>Grid based search<a class="headerlink" href="#grid-based-search" title="Permalink to this headline"></a></h1> +<section id="breadth-first-search"> +<h2>Breadth First Search<a class="headerlink" href="#breadth-first-search" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based path planning with Breadth first search algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BreadthFirstSearch/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BreadthFirstSearch/animation.gif" /> +<p>In the animation, cyan points are searched nodes.</p> +</section> +<section id="depth-first-search"> +<h2>Depth First Search<a class="headerlink" href="#depth-first-search" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based path planning with Depth first search algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DepthFirstSearch/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DepthFirstSearch/animation.gif" /> +<p>In the animation, cyan points are searched nodes.</p> +</section> +<section id="dijkstra-algorithm"> +<span id="dijkstra"></span><h2>Dijkstra algorithm<a class="headerlink" href="#dijkstra-algorithm" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based shortest path planning with Dijkstra’s algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/Dijkstra/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/Dijkstra/animation.gif" /> +<p>In the animation, cyan points are searched nodes.</p> +</section> +<section id="a-algorithm"> +<span id="id1"></span><h2>A* algorithm<a class="headerlink" href="#a-algorithm" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based shortest path planning with A star algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/AStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/AStar/animation.gif" /> +<p>In the animation, cyan points are searched nodes.</p> +<p>Its heuristic is 2D Euclid distance.</p> +</section> +<section id="bidirectional-a-algorithm"> +<h2>Bidirectional A* algorithm<a class="headerlink" href="#bidirectional-a-algorithm" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based shortest path planning with bidirectional A star algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BidirectionalAStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BidirectionalAStar/animation.gif" /> +<p>In the animation, cyan points are searched nodes.</p> +</section> +<section id="d-algorithm"> +<span id="id2"></span><h2>D* algorithm<a class="headerlink" href="#d-algorithm" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based shortest path planning with D star algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DStar/animation.gif" /> +<p>The animation shows a robot finding its path avoiding an obstacle using the D* search algorithm.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://en.wikipedia.org/wiki/D*">D* search Wikipedia</a></p></li> +</ul> +</section> +<section id="d-lite-algorithm"> +<h2>D* lite algorithm<a class="headerlink" href="#d-lite-algorithm" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based path planning and replanning with D star lite algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DStarLite/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/DStarLite/animation.gif" /> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.cs.cmu.edu/~maxim/files/dlite_icra02.pdf">Improved Fast Replanning for Robot Navigation in Unknown Terrain</a></p></li> +</ul> +</section> +<section id="potential-field-algorithm"> +<h2>Potential Field algorithm<a class="headerlink" href="#potential-field-algorithm" title="Permalink to this headline"></a></h2> +<p>This is a 2D grid based path planning with Potential Field algorithm.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/PotentialFieldPlanning/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/PotentialFieldPlanning/animation.gif" /> +<p>In the animation, the blue heat map shows potential value on each grid.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.cs.cmu.edu/~motionplanning/lecture/Chap4-Potential-Field_howie.pdf">Robotic Motion Planning:Potential +Functions</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../bugplanner/bugplanner.html" class="btn btn-neutral float-left" title="Bug planner" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html" class="btn btn-neutral float-right" title="Model Predictive Trajectory Generator" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/hybridastar/hybridastar.html b/modules/path_planning/hybridastar/hybridastar.html new file mode 100644 index 00000000000..b743874eda6 --- /dev/null +++ b/modules/path_planning/hybridastar/hybridastar.html @@ -0,0 +1,167 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Hybrid a star — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Optimal Trajectory in a Frenet Frame" href="../frenet_frame_path/frenet_frame_path.html" /> + <link rel="prev" title="LQR based path planning" href="../lqr_path/lqr_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Hybrid a star</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/hybridastar/hybridastar_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="hybrid-a-star"> +<h1>Hybrid a star<a class="headerlink" href="#hybrid-a-star" title="Permalink to this headline"></a></h1> +<p>This is a simple vehicle model based hybrid A* path planner.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/HybridAStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/HybridAStar/animation.gif" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../lqr_path/lqr_path.html" class="btn btn-neutral float-left" title="LQR based path planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../frenet_frame_path/frenet_frame_path.html" class="btn btn-neutral float-right" title="Optimal Trajectory in a Frenet Frame" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/lqr_path/lqr_path.html b/modules/path_planning/lqr_path/lqr_path.html new file mode 100644 index 00000000000..bfa72d349b3 --- /dev/null +++ b/modules/path_planning/lqr_path/lqr_path.html @@ -0,0 +1,167 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>LQR based path planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Hybrid a star" href="../hybridastar/hybridastar.html" /> + <link rel="prev" title="Reeds Shepp planning" href="../reeds_shepp_path/reeds_shepp_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>LQR based path planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/lqr_path/lqr_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="lqr-based-path-planning"> +<h1>LQR based path planning<a class="headerlink" href="#lqr-based-path-planning" title="Permalink to this headline"></a></h1> +<p>A sample code using LQR based path planning for double integrator model.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/LQRPlanner/animation.gif?raw=true" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/LQRPlanner/animation.gif?raw=true" /> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../reeds_shepp_path/reeds_shepp_path.html" class="btn btn-neutral float-left" title="Reeds Shepp planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../hybridastar/hybridastar.html" class="btn btn-neutral float-right" title="Hybrid a star" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator.html b/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator.html new file mode 100644 index 00000000000..c812e10bd4a --- /dev/null +++ b/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator.html @@ -0,0 +1,185 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Model Predictive Trajectory Generator — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="State Lattice Planning" href="../state_lattice_planner/state_lattice_planner.html" /> + <link rel="prev" title="Grid based search" href="../grid_base_search/grid_base_search.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Model Predictive Trajectory Generator</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#path-optimization-sample">Path optimization sample</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lookup-table-generation-sample">Lookup table generation sample</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Model Predictive Trajectory Generator</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="model-predictive-trajectory-generator"> +<h1>Model Predictive Trajectory Generator<a class="headerlink" href="#model-predictive-trajectory-generator" title="Permalink to this headline"></a></h1> +<p>This is a path optimization sample on model predictive trajectory +generator.</p> +<p>This algorithm is used for state lattice planner.</p> +<section id="path-optimization-sample"> +<h2>Path optimization sample<a class="headerlink" href="#path-optimization-sample" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ModelPredictiveTrajectoryGenerator/kn05animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ModelPredictiveTrajectoryGenerator/kn05animation.gif" /> +</section> +<section id="lookup-table-generation-sample"> +<h2>Lookup table generation sample<a class="headerlink" href="#lookup-table-generation-sample" title="Permalink to this headline"></a></h2> +<img alt="../../../_images/lookup_table.png" src="../../../_images/lookup_table.png" /> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://journals.sagepub.com/doi/pdf/10.1177/0278364906075328">Optimal rough terrain trajectory generation for wheeled mobile +robots</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../grid_base_search/grid_base_search.html" class="btn btn-neutral float-left" title="Grid based search" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../state_lattice_planner/state_lattice_planner.html" class="btn btn-neutral float-right" title="State Lattice Planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/path_planning.html b/modules/path_planning/path_planning.html new file mode 100644 index 00000000000..2afac5fb132 --- /dev/null +++ b/modules/path_planning/path_planning.html @@ -0,0 +1,256 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Path Planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Dynamic Window Approach" href="dynamic_window_approach/dynamic_window_approach.html" /> + <link rel="prev" title="Graph based SLAM" href="../slam/graph_slam/graph_slam.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Path Planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Path Planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/path_planning_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="path-planning"> +<span id="id1"></span><h1>Path Planning<a class="headerlink" href="#path-planning" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l1"><a class="reference internal" href="bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l1"><a class="reference internal" href="grid_base_search/grid_base_search.html">Grid based search</a><ul> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#breadth-first-search">Breadth First Search</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#depth-first-search">Depth First Search</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#dijkstra-algorithm">Dijkstra algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#a-algorithm">A* algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#bidirectional-a-algorithm">Bidirectional A* algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#d-algorithm">D* algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#d-lite-algorithm">D* lite algorithm</a></li> +<li class="toctree-l2"><a class="reference internal" href="grid_base_search/grid_base_search.html#potential-field-algorithm">Potential Field algorithm</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a><ul> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_trajectory_generator/model_predictive_trajectory_generator.html#path-optimization-sample">Path optimization sample</a></li> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_trajectory_generator/model_predictive_trajectory_generator.html#lookup-table-generation-sample">Lookup table generation sample</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="state_lattice_planner/state_lattice_planner.html#uniform-polar-sampling">Uniform polar sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="state_lattice_planner/state_lattice_planner.html#biased-polar-sampling">Biased polar sampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="state_lattice_planner/state_lattice_planner.html#lane-sampling">Lane sampling</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a><ul> +<li class="toctree-l2"><a class="reference internal" href="visibility_road_map_planner/visibility_road_map_planner.html#algorithms">Algorithms</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a><ul> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#basic-rrt">Basic RRT</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#rrt">RRT*</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#rrt-with-dubins-path">RRT with dubins path</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#id2">RRT* with dubins path</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#rrt-with-reeds-sheep-path">RRT* with reeds-sheep path</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#informed-rrt">Informed RRT*</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#batch-informed-rrt">Batch Informed RRT*</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#closed-loop-rrt">Closed Loop RRT*</a></li> +<li class="toctree-l2"><a class="reference internal" href="rrt/rrt.html#lqr-rrt">LQR-RRT*</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="cubic_spline/cubic_spline.html">Cubic spline planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="cubic_spline/cubic_spline.html#spline-curve-continuity">Spline curve continuity</a></li> +<li class="toctree-l2"><a class="reference internal" href="cubic_spline/cubic_spline.html#d-cubic-spline">1D cubic spline</a></li> +<li class="toctree-l2"><a class="reference internal" href="cubic_spline/cubic_spline.html#id1">2D cubic spline</a></li> +<li class="toctree-l2"><a class="reference internal" href="cubic_spline/cubic_spline.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="bspline_path/bspline_path.html">B-Spline planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="bspline_path/bspline_path.html#bspline-basics">Bspline basics</a></li> +<li class="toctree-l2"><a class="reference internal" href="bspline_path/bspline_path.html#bspline-interpolation-planning">Bspline interpolation planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="bspline_path/bspline_path.html#bspline-approximation-planning">Bspline approximation planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="bspline_path/bspline_path.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="clothoid_path/clothoid_path.html">Clothoid path planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="clothoid_path/clothoid_path.html#step1-solve-g-function">Step1: Solve g function</a></li> +<li class="toctree-l2"><a class="reference internal" href="clothoid_path/clothoid_path.html#step2-calculate-path-parameters">Step2: Calculate path parameters</a></li> +<li class="toctree-l2"><a class="reference internal" href="clothoid_path/clothoid_path.html#step3-construct-a-path-with-fresnel-integral">Step3: Construct a path with Fresnel integral</a></li> +<li class="toctree-l2"><a class="reference internal" href="clothoid_path/clothoid_path.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="quintic_polynomials_planner/quintic_polynomials_planner.html#quintic-polynomials-for-one-dimensional-robot-motion">Quintic polynomials for one dimensional robot motion</a></li> +<li class="toctree-l2"><a class="reference internal" href="quintic_polynomials_planner/quintic_polynomials_planner.html#quintic-polynomials-for-two-dimensional-robot-motion-x-y">Quintic polynomials for two dimensional robot motion (x-y)</a></li> +<li class="toctree-l2"><a class="reference internal" href="quintic_polynomials_planner/quintic_polynomials_planner.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="dubins_path/dubins_path.html">Dubins path planning</a><ul> +<li class="toctree-l2"><a class="reference internal" href="dubins_path/dubins_path.html#dubins-path">Dubins path</a></li> +<li class="toctree-l2"><a class="reference internal" href="dubins_path/dubins_path.html#api">API</a></li> +<li class="toctree-l2"><a class="reference internal" href="dubins_path/dubins_path.html#reference">Reference</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l1"><a class="reference internal" href="frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l1"><a class="reference internal" href="coverage_path/coverage_path.html">Coverage path planner</a><ul> +<li class="toctree-l2"><a class="reference internal" href="coverage_path/coverage_path.html#grid-based-sweep">Grid based sweep</a></li> +<li class="toctree-l2"><a class="reference internal" href="coverage_path/coverage_path.html#spiral-spanning-tree">Spiral Spanning Tree</a></li> +<li class="toctree-l2"><a class="reference internal" href="coverage_path/coverage_path.html#wavefront-path">Wavefront path</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../slam/graph_slam/graph_slam.html" class="btn btn-neutral float-left" title="Graph based SLAM" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="dynamic_window_approach/dynamic_window_approach.html" class="btn btn-neutral float-right" title="Dynamic Window Approach" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/prm_planner/prm_planner.html b/modules/path_planning/prm_planner/prm_planner.html new file mode 100644 index 00000000000..b149c14d3bf --- /dev/null +++ b/modules/path_planning/prm_planner/prm_planner.html @@ -0,0 +1,175 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Probabilistic Road-Map (PRM) planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Visibility Road-Map planner" href="../visibility_road_map_planner/visibility_road_map_planner.html" /> + <link rel="prev" title="State Lattice Planning" href="../state_lattice_planner/state_lattice_planner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Probabilistic Road-Map (PRM) planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/prm_planner/prm_planner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="probabilistic-road-map-prm-planning"> +<span id="id1"></span><h1>Probabilistic Road-Map (PRM) planning<a class="headerlink" href="#probabilistic-road-map-prm-planning" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ProbabilisticRoadMap/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ProbabilisticRoadMap/animation.gif" /> +<p>This PRM planner uses Dijkstra method for graph search.</p> +<p>In the animation, blue points are sampled points,</p> +<p>Cyan crosses means searched points with Dijkstra method,</p> +<p>The red line is the final path of PRM.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://en.wikipedia.org/wiki/Probabilistic_roadmap">Probabilistic roadmap - +Wikipedia</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../state_lattice_planner/state_lattice_planner.html" class="btn btn-neutral float-left" title="State Lattice Planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../visibility_road_map_planner/visibility_road_map_planner.html" class="btn btn-neutral float-right" title="Visibility Road-Map planner" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner.html b/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner.html new file mode 100644 index 00000000000..263ee9b7aca --- /dev/null +++ b/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner.html @@ -0,0 +1,235 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Quintic polynomials planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Dubins path planning" href="../dubins_path/dubins_path.html" /> + <link rel="prev" title="Bezier path planning" href="../bezier_path/bezier_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Quintic polynomials planning</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#quintic-polynomials-for-one-dimensional-robot-motion">Quintic polynomials for one dimensional robot motion</a></li> +<li class="toctree-l3"><a class="reference internal" href="#quintic-polynomials-for-two-dimensional-robot-motion-x-y">Quintic polynomials for two dimensional robot motion (x-y)</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Quintic polynomials planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="quintic-polynomials-planning"> +<h1>Quintic polynomials planning<a class="headerlink" href="#quintic-polynomials-planning" title="Permalink to this headline"></a></h1> +<p>Motion planning with quintic polynomials.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/QuinticPolynomialsPlanner/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/QuinticPolynomialsPlanner/animation.gif" /> +<p>It can calculate 2D path, velocity, and acceleration profile based on +quintic polynomials.</p> +<section id="quintic-polynomials-for-one-dimensional-robot-motion"> +<h2>Quintic polynomials for one dimensional robot motion<a class="headerlink" href="#quintic-polynomials-for-one-dimensional-robot-motion" title="Permalink to this headline"></a></h2> +<p>We assume a one-dimensional robot motion <span class="math notranslate nohighlight">\(x(t)\)</span> at time <span class="math notranslate nohighlight">\(t\)</span> is +formulated as a quintic polynomials based on time as follows:</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq1"> +<span class="eqno">(1)<a class="headerlink" href="#equation-quintic-eq1" title="Permalink to this equation"></a></span>\[x(t) = a_0+a_1t+a_2t^2+a_3t^3+a_4t^4+a_5t^5\]</div> +<p><span class="math notranslate nohighlight">\(a_0, a_1. a_2, a_3, a_4, a_5\)</span> are parameters of the quintic polynomial.</p> +<p>It is assumed that terminal states (start and end) are known as boundary conditions.</p> +<p>Start position, velocity, and acceleration are <span class="math notranslate nohighlight">\(x_s, v_s, a_s\)</span> respectively.</p> +<p>End position, velocity, and acceleration are <span class="math notranslate nohighlight">\(x_e, v_e, a_e\)</span> respectively.</p> +<p>So, when time is 0.</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq2"> +<span class="eqno">(2)<a class="headerlink" href="#equation-quintic-eq2" title="Permalink to this equation"></a></span>\[x(0) = a_0 = x_s\]</div> +<p>Then, differentiating the equation <a class="reference internal" href="#equation-quintic-eq1">(1)</a> with t,</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq3"> +<span class="eqno">(3)<a class="headerlink" href="#equation-quintic-eq3" title="Permalink to this equation"></a></span>\[x'(t) = a_1+2a_2t+3a_3t^2+4a_4t^3+5a_5t^4\]</div> +<p>So, when time is 0,</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq4"> +<span class="eqno">(4)<a class="headerlink" href="#equation-quintic-eq4" title="Permalink to this equation"></a></span>\[x'(0) = a_1 = v_s\]</div> +<p>Then, differentiating the equation <a class="reference internal" href="#equation-quintic-eq3">(3)</a> with t again,</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq5"> +<span class="eqno">(5)<a class="headerlink" href="#equation-quintic-eq5" title="Permalink to this equation"></a></span>\[x''(t) = 2a_2+6a_3t+12a_4t^2\]</div> +<p>So, when time is 0,</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq6"> +<span class="eqno">(6)<a class="headerlink" href="#equation-quintic-eq6" title="Permalink to this equation"></a></span>\[x''(0) = 2a_2 = a_s\]</div> +<p>so, we can calculate <span class="math notranslate nohighlight">\(a_0, a_1, a_2\)</span> with eq. <a class="reference internal" href="#equation-quintic-eq2">(2)</a>, <a class="reference internal" href="#equation-quintic-eq4">(4)</a>, <a class="reference internal" href="#equation-quintic-eq6">(6)</a> and boundary conditions.</p> +<p><span class="math notranslate nohighlight">\(a_3, a_4, a_5\)</span> are still unknown in eq <a class="reference internal" href="#equation-quintic-eq1">(1)</a>.</p> +<p>We assume that the end time for a maneuver is <span class="math notranslate nohighlight">\(T\)</span>, we can get these equations from eq <a class="reference internal" href="#equation-quintic-eq1">(1)</a>, <a class="reference internal" href="#equation-quintic-eq3">(3)</a>, <a class="reference internal" href="#equation-quintic-eq5">(5)</a>:</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq7"> +<span class="eqno">(7)<a class="headerlink" href="#equation-quintic-eq7" title="Permalink to this equation"></a></span>\[x(T)=a_0+a_1T+a_2T^2+a_3T^3+a_4T^4+a_5T^5=x_e\]</div> +<div class="math notranslate nohighlight" id="equation-quintic-eq8"> +<span class="eqno">(8)<a class="headerlink" href="#equation-quintic-eq8" title="Permalink to this equation"></a></span>\[x'(T)=a_1+2a_2T+3a_3T^2+4a_4T^3+5a_5T^4=v_e\]</div> +<div class="math notranslate nohighlight" id="equation-quintic-eq9"> +<span class="eqno">(9)<a class="headerlink" href="#equation-quintic-eq9" title="Permalink to this equation"></a></span>\[x''(T)=2a_2+6a_3T+12a_4T^2+20a_5T^3=a_e\]</div> +<p>From eq <a class="reference internal" href="#equation-quintic-eq7">(7)</a>, <a class="reference internal" href="#equation-quintic-eq8">(8)</a>, <a class="reference internal" href="#equation-quintic-eq9">(9)</a>, we can calculate <span class="math notranslate nohighlight">\(a_3, a_4, a_5\)</span> to solve the linear equations: <span class="math notranslate nohighlight">\(Ax=b\)</span></p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{bmatrix} T^3 & T^4 & T^5 \\ 3T^2 & 4T^3 & 5T^4 \\ 6T & 12T^2 & 20T^3 \end{bmatrix}\begin{bmatrix} a_3\\ a_4\\ a_5\end{bmatrix}=\begin{bmatrix} x_e-x_s-v_sT-0.5a_sT^2\\ v_e-v_s-a_sT\\ a_e-a_s\end{bmatrix}\end{split}\]</div> +<p>We can get all unknown parameters now.</p> +</section> +<section id="quintic-polynomials-for-two-dimensional-robot-motion-x-y"> +<h2>Quintic polynomials for two dimensional robot motion (x-y)<a class="headerlink" href="#quintic-polynomials-for-two-dimensional-robot-motion-x-y" title="Permalink to this headline"></a></h2> +<p>If you use two quintic polynomials along x axis and y axis, you can plan for two dimensional robot motion in x-y plane.</p> +<div class="math notranslate nohighlight" id="equation-quintic-eq10"> +<span class="eqno">(10)<a class="headerlink" href="#equation-quintic-eq10" title="Permalink to this equation"></a></span>\[x(t) = a_0+a_1t+a_2t^2+a_3t^3+a_4t^4+a_5t^5\]</div> +<div class="math notranslate nohighlight" id="equation-quintic-eq11"> +<span class="eqno">(11)<a class="headerlink" href="#equation-quintic-eq11" title="Permalink to this equation"></a></span>\[y(t) = b_0+b_1t+b_2t^2+b_3t^3+b_4t^4+b_5t^5\]</div> +<p>It is assumed that terminal states (start and end) are known as boundary conditions.</p> +<p>Start position, orientation, velocity, and acceleration are <span class="math notranslate nohighlight">\(x_s, y_s, \theta_s, v_s, a_s\)</span> respectively.</p> +<p>End position, orientation, velocity, and acceleration are <span class="math notranslate nohighlight">\(x_e, y_e. \theta_e, v_e, a_e\)</span> respectively.</p> +<p>Each velocity and acceleration boundary condition can be calculated with each orientation.</p> +<p><span class="math notranslate nohighlight">\(v_{xs}=v_scos(\theta_s), v_{ys}=v_ssin(\theta_s)\)</span></p> +<p><span class="math notranslate nohighlight">\(v_{xe}=v_ecos(\theta_e), v_{ye}=v_esin(\theta_e)\)</span></p> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://ieeexplore.ieee.org/document/637936/">Local Path Planning And Motion Control For Agv In +Positioning</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../bezier_path/bezier_path.html" class="btn btn-neutral float-left" title="Bezier path planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../dubins_path/dubins_path.html" class="btn btn-neutral float-right" title="Dubins path planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/reeds_shepp_path/reeds_shepp_path.html b/modules/path_planning/reeds_shepp_path/reeds_shepp_path.html new file mode 100644 index 00000000000..f80ca196603 --- /dev/null +++ b/modules/path_planning/reeds_shepp_path/reeds_shepp_path.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Reeds Shepp planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="LQR based path planning" href="../lqr_path/lqr_path.html" /> + <link rel="prev" title="Dubins path planning" href="../dubins_path/dubins_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Reeds Shepp planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/reeds_shepp_path/reeds_shepp_path_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="reeds-shepp-planning"> +<h1>Reeds Shepp planning<a class="headerlink" href="#reeds-shepp-planning" title="Permalink to this headline"></a></h1> +<p>A sample code with Reeds Shepp path planning.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ReedsSheppPath/animation.gif?raw=true" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ReedsSheppPath/animation.gif?raw=true" /> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://planning.cs.uiuc.edu/node822.html">15.3.2 Reeds-Shepp +Curves</a></p></li> +<li><p><a class="reference external" href="https://pdfs.semanticscholar.org/932e/c495b1d0018fd59dee12a0bf74434fac7af4.pdf">optimal paths for a car that goes both forwards and +backwards</a></p></li> +<li><p><a class="reference external" href="https://github.com/ghliu/pyReedsShepp">ghliu/pyReedsShepp: Implementation of Reeds Shepp +curve.</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../dubins_path/dubins_path.html" class="btn btn-neutral float-left" title="Dubins path planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../lqr_path/lqr_path.html" class="btn btn-neutral float-right" title="LQR based path planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/rrt/rrt.html b/modules/path_planning/rrt/rrt.html new file mode 100644 index 00000000000..3340af64316 --- /dev/null +++ b/modules/path_planning/rrt/rrt.html @@ -0,0 +1,274 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Rapidly-Exploring Random Trees (RRT) — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Cubic spline planning" href="../cubic_spline/cubic_spline.html" /> + <link rel="prev" title="Voronoi Road-Map planning" href="../vrm_planner/vrm_planner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Rapidly-Exploring Random Trees (RRT)</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#basic-rrt">Basic RRT</a></li> +<li class="toctree-l3"><a class="reference internal" href="#rrt">RRT*</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#simulation">Simulation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#ref">Ref</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#rrt-with-dubins-path">RRT with dubins path</a></li> +<li class="toctree-l3"><a class="reference internal" href="#id2">RRT* with dubins path</a></li> +<li class="toctree-l3"><a class="reference internal" href="#rrt-with-reeds-sheep-path">RRT* with reeds-sheep path</a></li> +<li class="toctree-l3"><a class="reference internal" href="#informed-rrt">Informed RRT*</a></li> +<li class="toctree-l3"><a class="reference internal" href="#batch-informed-rrt">Batch Informed RRT*</a></li> +<li class="toctree-l3"><a class="reference internal" href="#closed-loop-rrt">Closed Loop RRT*</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lqr-rrt">LQR-RRT*</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Rapidly-Exploring Random Trees (RRT)</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/rrt/rrt_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="rapidly-exploring-random-trees-rrt"> +<span id="id1"></span><h1>Rapidly-Exploring Random Trees (RRT)<a class="headerlink" href="#rapidly-exploring-random-trees-rrt" title="Permalink to this headline"></a></h1> +<section id="basic-rrt"> +<h2>Basic RRT<a class="headerlink" href="#basic-rrt" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRT/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRT/animation.gif" /> +<p>This is a simple path planning code with Rapidly-Exploring Random Trees +(RRT)</p> +<p>Black circles are obstacles, green line is a searched tree, red crosses +are start and goal positions.</p> +</section> +<section id="rrt"> +<h2>RRT*<a class="headerlink" href="#rrt" title="Permalink to this headline"></a></h2> +<figure class="align-default"> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTstar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTstar/animation.gif" /> +</figure> +<p>This is a path planning code with RRT*</p> +<p>Black circles are obstacles, green line is a searched tree, red crosses are start and goal positions.</p> +<section id="simulation"> +<h3>Simulation<a class="headerlink" href="#simulation" title="Permalink to this headline"></a></h3> +<a class="reference internal image-reference" href="../../../_images/rrt_star_1_0.png"><img alt="../../../_images/rrt_star_1_0.png" src="../../../_images/rrt_star_1_0.png" style="width: 600px;" /></a> +</section> +<section id="ref"> +<h3>Ref<a class="headerlink" href="#ref" title="Permalink to this headline"></a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://arxiv.org/pdf/1105.1186.pdf">Sampling-based Algorithms for Optimal Motion Planning</a></p></li> +<li><p><a class="reference external" href="https://arxiv.org/abs/1005.0416">Incremental Sampling-based Algorithms for Optimal Motion Planning</a></p></li> +</ul> +</section> +</section> +<section id="rrt-with-dubins-path"> +<h2>RRT with dubins path<a class="headerlink" href="#rrt-with-dubins-path" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTDubins/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTDubins/animation.gif" /> +<p>Path planning for a car robot with RRT and dubins path planner.</p> +</section> +<section id="id2"> +<span id="id3"></span><h2>RRT* with dubins path<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTStarDubins/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTStarDubins/animation.gif" /> +<p>Path planning for a car robot with RRT* and dubins path planner.</p> +</section> +<section id="rrt-with-reeds-sheep-path"> +<span id="id4"></span><h2>RRT* with reeds-sheep path<a class="headerlink" href="#rrt-with-reeds-sheep-path" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTStarReedsShepp/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/RRTStarReedsShepp/animation.gif" /> +<p>Path planning for a car robot with RRT* and reeds sheep path planner.</p> +</section> +<section id="informed-rrt"> +<span id="id5"></span><h2>Informed RRT*<a class="headerlink" href="#informed-rrt" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/InformedRRTStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/InformedRRTStar/animation.gif" /> +<p>This is a path planning code with Informed RRT*.</p> +<p>The cyan ellipse is the heuristic sampling domain of Informed RRT*.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://arxiv.org/pdf/1404.2334.pdf">Informed RRT*: Optimal Sampling-based Path Planning Focused via +Direct Sampling of an Admissible Ellipsoidal +Heuristic</a></p></li> +</ul> +</section> +<section id="batch-informed-rrt"> +<span id="id6"></span><h2>Batch Informed RRT*<a class="headerlink" href="#batch-informed-rrt" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BatchInformedRRTStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/BatchInformedRRTStar/animation.gif" /> +<p>This is a path planning code with Batch Informed RRT*.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://arxiv.org/abs/1405.5848">Batch Informed Trees (BIT*): Sampling-based Optimal Planning via the +Heuristically Guided Search of Implicit Random Geometric +Graphs</a></p></li> +</ul> +</section> +<section id="closed-loop-rrt"> +<span id="id7"></span><h2>Closed Loop RRT*<a class="headerlink" href="#closed-loop-rrt" title="Permalink to this headline"></a></h2> +<p>A vehicle model based path planning with closed loop RRT*.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClosedLoopRRTStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/ClosedLoopRRTStar/animation.gif" /> +<p>In this code, pure-pursuit algorithm is used for steering control,</p> +<p>PID is used for speed control.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://acl.mit.edu/papers/KuwataGNC08.pdf">Motion Planning in Complex Environments using Closed-loop +Prediction</a></p></li> +<li><p><a class="reference external" href="http://acl.mit.edu/papers/KuwataTCST09.pdf">Real-time Motion Planning with Applications to Autonomous Urban +Driving</a></p></li> +<li><p><a class="reference external" href="https://arxiv.org/abs/1601.06326">[1601.06326] Sampling-based Algorithms for Optimal Motion Planning +Using Closed-loop Prediction</a></p></li> +</ul> +</section> +<section id="lqr-rrt"> +<span id="id8"></span><h2>LQR-RRT*<a class="headerlink" href="#lqr-rrt" title="Permalink to this headline"></a></h2> +<p>This is a path planning simulation with LQR-RRT*.</p> +<p>A double integrator motion model is used for LQR local planner.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/LQRRRTStar/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/LQRRRTStar/animation.gif" /> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://lis.csail.mit.edu/pubs/perez-icra12.pdf">LQR-RRT*: Optimal Sampling-Based Motion Planning with Automatically +Derived Extension +Heuristics</a></p></li> +<li><p><a class="reference external" href="https://github.com/MahanFathi/LQR-RRTstar">MahanFathi/LQR-RRTstar: LQR-RRT* method is used for random motion planning of a simple pendulum in its phase plot</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../vrm_planner/vrm_planner.html" class="btn btn-neutral float-left" title="Voronoi Road-Map planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../cubic_spline/cubic_spline.html" class="btn btn-neutral float-right" title="Cubic spline planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/state_lattice_planner/state_lattice_planner.html b/modules/path_planning/state_lattice_planner/state_lattice_planner.html new file mode 100644 index 00000000000..ed9ab6700f0 --- /dev/null +++ b/modules/path_planning/state_lattice_planner/state_lattice_planner.html @@ -0,0 +1,193 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>State Lattice Planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Probabilistic Road-Map (PRM) planning" href="../prm_planner/prm_planner.html" /> + <link rel="prev" title="Model Predictive Trajectory Generator" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">State Lattice Planning</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#uniform-polar-sampling">Uniform polar sampling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#biased-polar-sampling">Biased polar sampling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#lane-sampling">Lane sampling</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>State Lattice Planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/state_lattice_planner/state_lattice_planner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="state-lattice-planning"> +<h1>State Lattice Planning<a class="headerlink" href="#state-lattice-planning" title="Permalink to this headline"></a></h1> +<p>This script is a path planning code with state lattice planning.</p> +<p>This code uses the model predictive trajectory generator to solve +boundary problem.</p> +<section id="uniform-polar-sampling"> +<h2>Uniform polar sampling<a class="headerlink" href="#uniform-polar-sampling" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/StateLatticePlanner/UniformPolarSampling.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/StateLatticePlanner/UniformPolarSampling.gif" /> +</section> +<section id="biased-polar-sampling"> +<h2>Biased polar sampling<a class="headerlink" href="#biased-polar-sampling" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/StateLatticePlanner/BiasedPolarSampling.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/StateLatticePlanner/BiasedPolarSampling.gif" /> +</section> +<section id="lane-sampling"> +<h2>Lane sampling<a class="headerlink" href="#lane-sampling" title="Permalink to this headline"></a></h2> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/StateLatticePlanner/LaneSampling.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/StateLatticePlanner/LaneSampling.gif" /> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://journals.sagepub.com/doi/pdf/10.1177/0278364906075328">Optimal rough terrain trajectory generation for wheeled mobile +robots</a></p></li> +<li><p><a class="reference external" href="http://www.frc.ri.cmu.edu/~alonzo/pubs/papers/JFR_08_SS_Sampling.pdf">State Space Sampling of Feasible Motions for High-Performance Mobile +Robot Navigation in Complex +Environments</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html" class="btn btn-neutral float-left" title="Model Predictive Trajectory Generator" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../prm_planner/prm_planner.html" class="btn btn-neutral float-right" title="Probabilistic Road-Map (PRM) planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/visibility_road_map_planner/visibility_road_map_planner.html b/modules/path_planning/visibility_road_map_planner/visibility_road_map_planner.html new file mode 100644 index 00000000000..7389c299b1c --- /dev/null +++ b/modules/path_planning/visibility_road_map_planner/visibility_road_map_planner.html @@ -0,0 +1,226 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Visibility Road-Map planner — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Voronoi Road-Map planning" href="../vrm_planner/vrm_planner.html" /> + <link rel="prev" title="Probabilistic Road-Map (PRM) planning" href="../prm_planner/prm_planner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Visibility Road-Map planner</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#algorithms">Algorithms</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#step1-generate-visibility-nodes-based-on-polygon-obstacles">Step1: Generate visibility nodes based on polygon obstacles</a></li> +<li class="toctree-l4"><a class="reference internal" href="#step2-generate-visibility-graphs-connecting-the-nodes">Step2: Generate visibility graphs connecting the nodes.</a></li> +<li class="toctree-l4"><a class="reference internal" href="#step3-search-the-shortest-path-in-the-graphs-using-dijkstra-algorithm">Step3: Search the shortest path in the graphs using Dijkstra algorithm</a></li> +<li class="toctree-l4"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../vrm_planner/vrm_planner.html">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Visibility Road-Map planner</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/visibility_road_map_planner/visibility_road_map_planner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="visibility-road-map-planner"> +<h1>Visibility Road-Map planner<a class="headerlink" href="#visibility-road-map-planner" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/VisibilityRoadMap/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/VisibilityRoadMap/animation.gif" /> +<p><a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathPlanning/VisibilityRoadMap/visibility_road_map.py">[Code]</a></p> +<p>This visibility road-map planner uses Dijkstra method for graph search.</p> +<p>In the animation, the black lines are polygon obstacles,</p> +<p>red crosses are visibility nodes, and blue lines area collision free visibility graphs.</p> +<p>The red line is the final path searched by dijkstra algorithm frm the visibility graphs.</p> +<section id="algorithms"> +<h2>Algorithms<a class="headerlink" href="#algorithms" title="Permalink to this headline"></a></h2> +<p>In this chapter, how does the visibility road map planner search a path.</p> +<p>We assume this planner can be provided these information in the below figure.</p> +<ul class="simple"> +<li><ol class="arabic simple"> +<li><p>Start point (Red point)</p></li> +</ol> +</li> +<li><ol class="arabic simple" start="2"> +<li><p>Goal point (Blue point)</p></li> +</ol> +</li> +<li><ol class="arabic simple" start="3"> +<li><p>Obstacle polygons (Black lines)</p></li> +</ol> +</li> +</ul> +<a class="reference internal image-reference" href="../../../_images/step0.png"><img alt="../../../_images/step0.png" src="../../../_images/step0.png" style="width: 400px;" /></a> +<section id="step1-generate-visibility-nodes-based-on-polygon-obstacles"> +<h3>Step1: Generate visibility nodes based on polygon obstacles<a class="headerlink" href="#step1-generate-visibility-nodes-based-on-polygon-obstacles" title="Permalink to this headline"></a></h3> +<p>The nodes are generated by expanded these polygons vertexes like the below figure:</p> +<a class="reference internal image-reference" href="../../../_images/step1.png"><img alt="../../../_images/step1.png" src="../../../_images/step1.png" style="width: 400px;" /></a> +<p>Each polygon vertex is expanded outward from the vector of adjacent vertices.</p> +<p>The start and goal point are included as nodes as well.</p> +</section> +<section id="step2-generate-visibility-graphs-connecting-the-nodes"> +<h3>Step2: Generate visibility graphs connecting the nodes.<a class="headerlink" href="#step2-generate-visibility-graphs-connecting-the-nodes" title="Permalink to this headline"></a></h3> +<p>When connecting the nodes, the arc between two nodes is checked to collided or not to each obstacles.</p> +<p>If the arc is collided, the graph is removed.</p> +<p>The blue lines are generated visibility graphs in the figure:</p> +<a class="reference internal image-reference" href="../../../_images/step2.png"><img alt="../../../_images/step2.png" src="../../../_images/step2.png" style="width: 400px;" /></a> +</section> +<section id="step3-search-the-shortest-path-in-the-graphs-using-dijkstra-algorithm"> +<h3>Step3: Search the shortest path in the graphs using Dijkstra algorithm<a class="headerlink" href="#step3-search-the-shortest-path-in-the-graphs-using-dijkstra-algorithm" title="Permalink to this headline"></a></h3> +<p>The red line is searched path in the figure:</p> +<a class="reference internal image-reference" href="../../../_images/step3.png"><img alt="../../../_images/step3.png" src="../../../_images/step3.png" style="width: 400px;" /></a> +<p>You can find the details of Dijkstra algorithm in <a class="reference internal" href="../grid_base_search/grid_base_search.html#dijkstra"><span class="std std-ref">Dijkstra algorithm</span></a>.</p> +</section> +<section id="references"> +<h3>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://en.wikipedia.org/wiki/Visibility_graph">Visibility graph - Wikipedia</a></p></li> +</ul> +</section> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../prm_planner/prm_planner.html" class="btn btn-neutral float-left" title="Probabilistic Road-Map (PRM) planning" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../vrm_planner/vrm_planner.html" class="btn btn-neutral float-right" title="Voronoi Road-Map planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_planning/vrm_planner/vrm_planner.html b/modules/path_planning/vrm_planner/vrm_planner.html new file mode 100644 index 00000000000..9744d729b23 --- /dev/null +++ b/modules/path_planning/vrm_planner/vrm_planner.html @@ -0,0 +1,174 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Voronoi Road-Map planning — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Rapidly-Exploring Random Trees (RRT)" href="../rrt/rrt.html" /> + <link rel="prev" title="Visibility Road-Map planner" href="../visibility_road_map_planner/visibility_road_map_planner.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_planning.html">Path Planning</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../dynamic_window_approach/dynamic_window_approach.html">Dynamic Window Approach</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bugplanner/bugplanner.html">Bug planner</a></li> +<li class="toctree-l2"><a class="reference internal" href="../grid_base_search/grid_base_search.html">Grid based search</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_trajectory_generator/model_predictive_trajectory_generator.html">Model Predictive Trajectory Generator</a></li> +<li class="toctree-l2"><a class="reference internal" href="../state_lattice_planner/state_lattice_planner.html">State Lattice Planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../prm_planner/prm_planner.html">Probabilistic Road-Map (PRM) planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../visibility_road_map_planner/visibility_road_map_planner.html">Visibility Road-Map planner</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Voronoi Road-Map planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rrt/rrt.html">Rapidly-Exploring Random Trees (RRT)</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cubic_spline/cubic_spline.html">Cubic spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bspline_path/bspline_path.html">B-Spline planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../clothoid_path/clothoid_path.html">Clothoid path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../eta3_spline/eta3_spline.html">Eta^3 Spline path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../bezier_path/bezier_path.html">Bezier path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../quintic_polynomials_planner/quintic_polynomials_planner.html">Quintic polynomials planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../dubins_path/dubins_path.html">Dubins path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../reeds_shepp_path/reeds_shepp_path.html">Reeds Shepp planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_path/lqr_path.html">LQR based path planning</a></li> +<li class="toctree-l2"><a class="reference internal" href="../hybridastar/hybridastar.html">Hybrid a star</a></li> +<li class="toctree-l2"><a class="reference internal" href="../frenet_frame_path/frenet_frame_path.html">Optimal Trajectory in a Frenet Frame</a></li> +<li class="toctree-l2"><a class="reference internal" href="../coverage_path/coverage_path.html">Coverage path planner</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_planning.html">Path Planning</a> »</li> + <li>Voronoi Road-Map planning</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_planning/vrm_planner/vrm_planner_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="voronoi-road-map-planning"> +<h1>Voronoi Road-Map planning<a class="headerlink" href="#voronoi-road-map-planning" title="Permalink to this headline"></a></h1> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/VoronoiRoadMap/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathPlanning/VoronoiRoadMap/animation.gif" /> +<p>This Voronoi road-map planner uses Dijkstra method for graph search.</p> +<p>In the animation, blue points are Voronoi points,</p> +<p>Cyan crosses mean searched points with Dijkstra method,</p> +<p>The red line is the final path of Vornoi Road-Map.</p> +<p>Ref:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://www.cs.cmu.edu/~motionplanning/lecture/Chap5-RoadMap-Methods_howie.pdf">Robotic Motion Planning</a></p></li> +</ul> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../visibility_road_map_planner/visibility_road_map_planner.html" class="btn btn-neutral float-left" title="Visibility Road-Map planner" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../rrt/rrt.html" class="btn btn-neutral float-right" title="Rapidly-Exploring Random Trees (RRT)" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/cgmres_nmpc/cgmres_nmpc.html b/modules/path_tracking/cgmres_nmpc/cgmres_nmpc.html new file mode 100644 index 00000000000..36b079f96e0 --- /dev/null +++ b/modules/path_tracking/cgmres_nmpc/cgmres_nmpc.html @@ -0,0 +1,201 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Nonlinear Model Predictive Control with C-GMRES — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Arm Navigation" href="../../arm_navigation/arm_navigation.html" /> + <link rel="prev" title="Model predictive speed and steering control" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="../stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Nonlinear Model Predictive Control with C-GMRES</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#mathematical-formulation">Mathematical Formulation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#ref">Ref</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Nonlinear Model Predictive Control with C-GMRES</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="nonlinear-model-predictive-control-with-c-gmres"> +<h1>Nonlinear Model Predictive Control with C-GMRES<a class="headerlink" href="#nonlinear-model-predictive-control-with-c-gmres" title="Permalink to this headline"></a></h1> +<a class="reference internal image-reference" href="../../../_images/cgmres_nmpc_1_0.png"><img alt="../../../_images/cgmres_nmpc_1_0.png" src="../../../_images/cgmres_nmpc_1_0.png" style="width: 600px;" /></a> +<a class="reference internal image-reference" href="../../../_images/cgmres_nmpc_2_0.png"><img alt="../../../_images/cgmres_nmpc_2_0.png" src="../../../_images/cgmres_nmpc_2_0.png" style="width: 600px;" /></a> +<a class="reference internal image-reference" href="../../../_images/cgmres_nmpc_3_0.png"><img alt="../../../_images/cgmres_nmpc_3_0.png" src="../../../_images/cgmres_nmpc_3_0.png" style="width: 600px;" /></a> +<a class="reference internal image-reference" href="../../../_images/cgmres_nmpc_4_0.png"><img alt="../../../_images/cgmres_nmpc_4_0.png" src="../../../_images/cgmres_nmpc_4_0.png" style="width: 600px;" /></a> +<figure class="align-default"> +<img alt="gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/cgmres_nmpc/animation.gif" /> +</figure> +<section id="mathematical-formulation"> +<h2>Mathematical Formulation<a class="headerlink" href="#mathematical-formulation" title="Permalink to this headline"></a></h2> +<p>Motion model is</p> +<div class="math notranslate nohighlight"> +\[\dot{x}=vcos\theta\]</div> +<div class="math notranslate nohighlight"> +\[\dot{y}=vsin\theta\]</div> +<div class="math notranslate nohighlight"> +\[\dot{\theta}=\frac{v}{WB}sin(u_{\delta})\]</div> +<p>(tan is not good for optimization)</p> +<div class="math notranslate nohighlight"> +\[\dot{v}=u_a\]</div> +<p>Cost function is</p> +<div class="math notranslate nohighlight"> +\[J=\frac{1}{2}(u_a^2+u_{\delta}^2)-\phi_a d_a-\phi_\delta d_\delta\]</div> +<p>Input constraints are</p> +<div class="math notranslate nohighlight"> +\[|u_a| \leq u_{a,max}\]</div> +<div class="math notranslate nohighlight"> +\[|u_\delta| \leq u_{\delta,max}\]</div> +<p>So, Hamiltonian is</p> +<div class="math notranslate nohighlight"> +\[\begin{split}J=\frac{1}{2}(u_a^2+u_{\delta}^2)-\phi_a d_a-\phi_\delta d_\delta\\ +\lambda_1vcos\theta+\lambda_2vsin\theta+\lambda_3\frac{v}{WB}sin(u_{\delta})+\lambda_4u_a\\ ++\rho_1(u_a^2+d_a^2+u_{a,max}^2)+\rho_2(u_\delta^2+d_\delta^2+u_{\delta,max}^2)\end{split}\]</div> +<p>Partial differential equations of the Hamiltonian are:</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} \frac{\partial H}{\partial \bf{x}}=\\ \begin{bmatrix} \frac{\partial H}{\partial x}= 0&\\ \frac{\partial H}{\partial y}= 0&\\ \frac{\partial H}{\partial \theta}= -\lambda_1vsin\theta+\lambda_2vcos\theta&\\ \frac{\partial H}{\partial v}=-\lambda_1cos\theta+\lambda_2sin\theta+\lambda_3\frac{1}{WB}sin(u_{\delta})&\\ \end{bmatrix} \\ \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} \frac{\partial H}{\partial \bf{u}}=\\ \begin{bmatrix} \frac{\partial H}{\partial u_a}= u_a+\lambda_4+2\rho_1u_a&\\ \frac{\partial H}{\partial u_\delta}= u_\delta+\lambda_3\frac{v}{WB}cos(u_{\delta})+2\rho_2u_\delta&\\ \frac{\partial H}{\partial d_a}= -\phi_a+2\rho_1d_a&\\ \frac{\partial H}{\partial d_\delta}=-\phi_\delta+2\rho_2d_\delta&\\ \end{bmatrix} \\ \end{equation*}\)</span></p> +</section> +<section id="ref"> +<h2>Ref<a class="headerlink" href="#ref" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/Shunichi09/nonlinear_control">Shunichi09/nonlinear_control: Implementing the nonlinear model +predictive control, sliding mode +control</a></p></li> +<li><p><a class="reference external" href="https://qiita.com/MENDY/items/4108190a579395053924">非線形モデル予測制御におけるCGMRES法をpythonで実装する - +Qiita</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html" class="btn btn-neutral float-left" title="Model predictive speed and steering control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../arm_navigation/arm_navigation.html" class="btn btn-neutral float-right" title="Arm Navigation" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control.html b/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control.html new file mode 100644 index 00000000000..66dbb838a07 --- /dev/null +++ b/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control.html @@ -0,0 +1,162 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Linear–quadratic regulator (LQR) speed and steering control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Model predictive speed and steering control" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html" /> + <link rel="prev" title="Linear–quadratic regulator (LQR) steering control" href="../lqr_steering_control/lqr_steering_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="../stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Linear–quadratic regulator (LQR) speed and steering control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Linear–quadratic regulator (LQR) speed and steering control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="linearquadratic-regulator-lqr-speed-and-steering-control"> +<span id="id1"></span><h1>Linear–quadratic regulator (LQR) speed and steering control<a class="headerlink" href="#linearquadratic-regulator-lqr-speed-and-steering-control" title="Permalink to this headline"></a></h1> +<p>Path tracking simulation with LQR speed and steering control.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_speed_steer_control/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_speed_steer_control/animation.gif" /> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://ieeexplore.ieee.org/document/5940562/">Towards fully autonomous driving: Systems and algorithms</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../lqr_steering_control/lqr_steering_control.html" class="btn btn-neutral float-left" title="Linear–quadratic regulator (LQR) steering control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html" class="btn btn-neutral float-right" title="Model predictive speed and steering control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/lqr_steering_control/lqr_steering_control.html b/modules/path_tracking/lqr_steering_control/lqr_steering_control.html new file mode 100644 index 00000000000..5fe51907a10 --- /dev/null +++ b/modules/path_tracking/lqr_steering_control/lqr_steering_control.html @@ -0,0 +1,163 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Linear–quadratic regulator (LQR) steering control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Linear–quadratic regulator (LQR) speed and steering control" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html" /> + <link rel="prev" title="Rear wheel feedback control" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="../stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Linear–quadratic regulator (LQR) steering control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Linear–quadratic regulator (LQR) steering control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/lqr_steering_control/lqr_steering_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="linearquadratic-regulator-lqr-steering-control"> +<span id="id1"></span><h1>Linear–quadratic regulator (LQR) steering control<a class="headerlink" href="#linearquadratic-regulator-lqr-steering-control" title="Permalink to this headline"></a></h1> +<p>Path tracking simulation with LQR steering control and PID speed +control.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_steer_control/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/lqr_steer_control/animation.gif" /> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/ApolloAuto/apollo">ApolloAuto/apollo: An open autonomous driving platform</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html" class="btn btn-neutral float-left" title="Rear wheel feedback control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html" class="btn btn-neutral float-right" title="Linear–quadratic regulator (LQR) speed and steering control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html b/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html new file mode 100644 index 00000000000..75895c94d06 --- /dev/null +++ b/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html @@ -0,0 +1,271 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Model predictive speed and steering control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Nonlinear Model Predictive Control with C-GMRES" href="../cgmres_nmpc/cgmres_nmpc.html" /> + <link rel="prev" title="Linear–quadratic regulator (LQR) speed and steering control" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="../stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Model predictive speed and steering control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#mpc-modeling">MPC modeling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#vehicle-model-linearization">Vehicle model linearization</a></li> +<li class="toctree-l3"><a class="reference internal" href="#reference">Reference</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Model predictive speed and steering control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="model-predictive-speed-and-steering-control"> +<h1>Model predictive speed and steering control<a class="headerlink" href="#model-predictive-speed-and-steering-control" title="Permalink to this headline"></a></h1> +<figure class="align-default" id="id1"> +<img alt="Model predictive speed and steering control" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/model_predictive_speed_and_steer_control/animation.gif?raw=true" /> +<figcaption> +<p><span class="caption-text">Model predictive speed and steering control</span><a class="headerlink" href="#id1" title="Permalink to this image"></a></p> +</figcaption> +</figure> +<p>code:</p> +<p><a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathTracking/model_predictive_speed_and_steer_control/model_predictive_speed_and_steer_control.py">PythonRobotics/model_predictive_speed_and_steer_control.py at master · +AtsushiSakai/PythonRobotics</a></p> +<p>This is a path tracking simulation using model predictive control (MPC).</p> +<p>The MPC controller controls vehicle speed and steering base on +linearized model.</p> +<p>This code uses cvxpy as an optimization modeling tool.</p> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.cvxpy.org/">Welcome to CVXPY 1.0 — CVXPY 1.0.6 +documentation</a></p></li> +</ul> +<section id="mpc-modeling"> +<h2>MPC modeling<a class="headerlink" href="#mpc-modeling" title="Permalink to this headline"></a></h2> +<p>State vector is:</p> +<div class="math notranslate nohighlight"> +\[z = [x, y, v,\phi]\]</div> +<p>x: x-position, y:y-position, v:velocity, φ: yaw angle</p> +<p>Input vector is:</p> +<div class="math notranslate nohighlight"> +\[u = [a, \delta]\]</div> +<p>a: accellation, δ: steering angle</p> +<p>The MPC cotroller minimize this cost function for path tracking:</p> +<div class="math notranslate nohighlight"> +\[min\ Q_f(z_{T,ref}-z_{T})^2+Q\Sigma({z_{t,ref}-z_{t}})^2+R\Sigma{u_t}^2+R_d\Sigma({u_{t+1}-u_{t}})^2\]</div> +<p>z_ref come from target path and speed.</p> +<p>subject to:</p> +<ul class="simple"> +<li><p>Linearlied vehicle model</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[z_{t+1}=Az_t+Bu+C\]</div> +<ul class="simple"> +<li><p>Maximum steering speed</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[|u_{t+1}-u_{t}|<du_{max}\]</div> +<ul class="simple"> +<li><p>Maximum steering angle</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[|u_{t}|<u_{max}\]</div> +<ul class="simple"> +<li><p>Initial state</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[z_0 = z_{0,ob}\]</div> +<ul class="simple"> +<li><p>Maximum and minimum speed</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[v_{min} < v_t < v_{max}\]</div> +<ul class="simple"> +<li><p>Maximum and minimum input</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[u_{min} < u_t < u_{max}\]</div> +<p>This is implemented at</p> +<p><a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/f51a73f47cb922a12659f8ce2d544c347a2a8156/PathTracking/model_predictive_speed_and_steer_control/model_predictive_speed_and_steer_control.py#L247-L301">PythonRobotics/model_predictive_speed_and_steer_control.py at +f51a73f47cb922a12659f8ce2d544c347a2a8156 · +AtsushiSakai/PythonRobotics</a></p> +</section> +<section id="vehicle-model-linearization"> +<h2>Vehicle model linearization<a class="headerlink" href="#vehicle-model-linearization" title="Permalink to this headline"></a></h2> +<p>Vehicle model is</p> +<div class="math notranslate nohighlight"> +\[\dot{x} = vcos(\phi)\]</div> +<div class="math notranslate nohighlight"> +\[\dot{y} = vsin((\phi)\]</div> +<div class="math notranslate nohighlight"> +\[\dot{v} = a\]</div> +<div class="math notranslate nohighlight"> +\[\dot{\phi} = \frac{vtan(\delta)}{L}\]</div> +<p>ODE is</p> +<div class="math notranslate nohighlight"> +\[\dot{z} =\frac{\partial }{\partial z} z = f(z, u) = A'z+B'u\]</div> +<p>where</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} A' = \begin{bmatrix} \frac{\partial }{\partial x}vcos(\phi) & \frac{\partial }{\partial y}vcos(\phi) & \frac{\partial }{\partial v}vcos(\phi) & \frac{\partial }{\partial \phi}vcos(\phi)\\ \frac{\partial }{\partial x}vsin(\phi) & \frac{\partial }{\partial y}vsin(\phi) & \frac{\partial }{\partial v}vsin(\phi) & \frac{\partial }{\partial \phi}vsin(\phi)\\ \frac{\partial }{\partial x}a& \frac{\partial }{\partial y}a& \frac{\partial }{\partial v}a& \frac{\partial }{\partial \phi}a\\ \frac{\partial }{\partial x}\frac{vtan(\delta)}{L}& \frac{\partial }{\partial y}\frac{vtan(\delta)}{L}& \frac{\partial }{\partial v}\frac{vtan(\delta)}{L}& \frac{\partial }{\partial \phi}\frac{vtan(\delta)}{L}\\ \end{bmatrix} \\ = \begin{bmatrix} 0 & 0 & cos(\bar{\phi}) & -\bar{v}sin(\bar{\phi})\\ 0 & 0 & sin(\bar{\phi}) & \bar{v}cos(\bar{\phi}) \\ 0 & 0 & 0 & 0 \\ 0 & 0 &\frac{tan(\bar{\delta})}{L} & 0 \\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} B' = \begin{bmatrix} \frac{\partial }{\partial a}vcos(\phi) & \frac{\partial }{\partial \delta}vcos(\phi)\\ \frac{\partial }{\partial a}vsin(\phi) & \frac{\partial }{\partial \delta}vsin(\phi)\\ \frac{\partial }{\partial a}a & \frac{\partial }{\partial \delta}a\\ \frac{\partial }{\partial a}\frac{vtan(\delta)}{L} & \frac{\partial }{\partial \delta}\frac{vtan(\delta)}{L}\\ \end{bmatrix} \\ = \begin{bmatrix} 0 & 0 \\ 0 & 0 \\ 1 & 0 \\ 0 & \frac{\bar{v}}{Lcos^2(\bar{\delta})} \\ \end{bmatrix} \end{equation*}\)</span></p> +<p>You can get a discrete-time mode with Forward Euler Discretization with +sampling time dt.</p> +<div class="math notranslate nohighlight"> +\[z_{k+1}=z_k+f(z_k,u_k)dt\]</div> +<p>Using first degree Tayer expantion around zbar and ubar</p> +<div class="math notranslate nohighlight"> +\[z_{k+1}=z_k+(f(\bar{z},\bar{u})+A'z_k+B'u_k-A'\bar{z}-B'\bar{u})dt\]</div> +<div class="math notranslate nohighlight"> +\[z_{k+1}=(I + dtA')z_k+(dtB')u_k + (f(\bar{z},\bar{u})-A'\bar{z}-B'\bar{u})dt\]</div> +<p>So,</p> +<div class="math notranslate nohighlight"> +\[z_{k+1}=Az_k+Bu_k +C\]</div> +<p>where,</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} A = (I + dtA')\\ = \begin{bmatrix} 1 & 0 & cos(\bar{\phi})dt & -\bar{v}sin(\bar{\phi})dt\\ 0 & 1 & sin(\bar{\phi})dt & \bar{v}cos(\bar{\phi})dt \\ 0 & 0 & 1 & 0 \\ 0 & 0 &\frac{tan(\bar{\delta})}{L}dt & 1 \\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} B = dtB'\\ = \begin{bmatrix} 0 & 0 \\ 0 & 0 \\ dt & 0 \\ 0 & \frac{\bar{v}}{Lcos^2(\bar{\delta})}dt \\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} C = (f(\bar{z},\bar{u})-A'\bar{z}-B'\bar{u})dt\\ = dt( \begin{bmatrix} \bar{v}cos(\bar{\phi})\\ \bar{v}sin(\bar{\phi}) \\ \bar{a}\\ \frac{\bar{v}tan(\bar{\delta})}{L}\\ \end{bmatrix} - \begin{bmatrix} \bar{v}cos(\bar{\phi})-\bar{v}sin(\bar{\phi})\bar{\phi}\\ \bar{v}sin(\bar{\phi})+\bar{v}cos(\bar{\phi})\bar{\phi}\\ 0\\ \frac{\bar{v}tan(\bar{\delta})}{L}\\ \end{bmatrix} - \begin{bmatrix} 0\\ 0 \\ \bar{a}\\ \frac{\bar{v}\bar{\delta}}{Lcos^2(\bar{\delta})}\\ \end{bmatrix} )\\ = \begin{bmatrix} \bar{v}sin(\bar{\phi})\bar{\phi}dt\\ -\bar{v}cos(\bar{\phi})\bar{\phi}dt\\ 0\\ -\frac{\bar{v}\bar{\delta}}{Lcos^2(\bar{\delta})}dt\\ \end{bmatrix} \end{equation*}\)</span></p> +<p>This equation is implemented at</p> +<p><a class="reference external" href="https://github.com/AtsushiSakai/PythonRobotics/blob/eb6d1cbe6fc90c7be9210bf153b3a04f177cc138/PathTracking/model_predictive_speed_and_steer_control/model_predictive_speed_and_steer_control.py#L80-L102">PythonRobotics/model_predictive_speed_and_steer_control.py at +eb6d1cbe6fc90c7be9210bf153b3a04f177cc138 · +AtsushiSakai/PythonRobotics</a></p> +</section> +<section id="reference"> +<h2>Reference<a class="headerlink" href="#reference" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.springer.com/us/book/9781461414322">Vehicle Dynamics and Control | Rajesh Rajamani | +Springer</a></p></li> +<li><p><a class="reference external" href="http://www.mpc.berkeley.edu/mpc-course-material">MPC Course Material - MPC Lab @ +UC-Berkeley</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html" class="btn btn-neutral float-left" title="Linear–quadratic regulator (LQR) speed and steering control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../cgmres_nmpc/cgmres_nmpc.html" class="btn btn-neutral float-right" title="Nonlinear Model Predictive Control with C-GMRES" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/path_tracking.html b/modules/path_tracking/path_tracking.html new file mode 100644 index 00000000000..b89c48a67cc --- /dev/null +++ b/modules/path_tracking/path_tracking.html @@ -0,0 +1,186 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Path Tracking — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Pure pursuit tracking" href="pure_pursuit_tracking/pure_pursuit_tracking.html" /> + <link rel="prev" title="Coverage path planner" href="../path_planning/coverage_path/coverage_path.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Path Tracking</a><ul> +<li class="toctree-l2"><a class="reference internal" href="pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Path Tracking</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/path_tracking_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="path-tracking"> +<span id="id1"></span><h1>Path Tracking<a class="headerlink" href="#path-tracking" title="Permalink to this headline"></a></h1> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a><ul> +<li class="toctree-l2"><a class="reference internal" href="pure_pursuit_tracking/pure_pursuit_tracking.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="stanley_control/stanley_control.html">Stanley control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="stanley_control/stanley_control.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="rear_wheel_feedback_control/rear_wheel_feedback_control.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lqr_steering_control/lqr_steering_control.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lqr_speed_and_steering_control/lqr_speed_and_steering_control.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a><ul> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html#mpc-modeling">MPC modeling</a></li> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html#vehicle-model-linearization">Vehicle model linearization</a></li> +<li class="toctree-l2"><a class="reference internal" href="model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html#reference">Reference</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a><ul> +<li class="toctree-l2"><a class="reference internal" href="cgmres_nmpc/cgmres_nmpc.html#mathematical-formulation">Mathematical Formulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="cgmres_nmpc/cgmres_nmpc.html#ref">Ref</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../path_planning/coverage_path/coverage_path.html" class="btn btn-neutral float-left" title="Coverage path planner" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="pure_pursuit_tracking/pure_pursuit_tracking.html" class="btn btn-neutral float-right" title="Pure pursuit tracking" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking.html b/modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking.html new file mode 100644 index 00000000000..05f35b4fac7 --- /dev/null +++ b/modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking.html @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Pure pursuit tracking — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Stanley control" href="../stanley_control/stanley_control.html" /> + <link rel="prev" title="Path Tracking" href="../path_tracking.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Pure pursuit tracking</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Pure pursuit tracking</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="pure-pursuit-tracking"> +<h1>Pure pursuit tracking<a class="headerlink" href="#pure-pursuit-tracking" title="Permalink to this headline"></a></h1> +<p>Path tracking simulation with pure pursuit steering control and PID +speed control.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/pure_pursuit/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/pure_pursuit/animation.gif" /> +<p>The red line is a target course, the green cross means the target point +for pure pursuit control, the blue line is the tracking.</p> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://arxiv.org/abs/1604.07446">A Survey of Motion Planning and Control Techniques for Self-driving +Urban Vehicles</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../path_tracking.html" class="btn btn-neutral float-left" title="Path Tracking" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../stanley_control/stanley_control.html" class="btn btn-neutral float-right" title="Stanley control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control.html b/modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control.html new file mode 100644 index 00000000000..51d52456fd9 --- /dev/null +++ b/modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control.html @@ -0,0 +1,164 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Rear wheel feedback control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Linear–quadratic regulator (LQR) steering control" href="../lqr_steering_control/lqr_steering_control.html" /> + <link rel="prev" title="Stanley control" href="../stanley_control/stanley_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2"><a class="reference internal" href="../stanley_control/stanley_control.html">Stanley control</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Rear wheel feedback control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Rear wheel feedback control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="rear-wheel-feedback-control"> +<h1>Rear wheel feedback control<a class="headerlink" href="#rear-wheel-feedback-control" title="Permalink to this headline"></a></h1> +<p>Path tracking simulation with rear wheel feedback steering control and +PID speed control.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/rear_wheel_feedback/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/rear_wheel_feedback/animation.gif" /> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://arxiv.org/abs/1604.07446">A Survey of Motion Planning and Control Techniques for Self-driving +Urban Vehicles</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../stanley_control/stanley_control.html" class="btn btn-neutral float-left" title="Stanley control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../lqr_steering_control/lqr_steering_control.html" class="btn btn-neutral float-right" title="Linear–quadratic regulator (LQR) steering control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/path_tracking/stanley_control/stanley_control.html b/modules/path_tracking/stanley_control/stanley_control.html new file mode 100644 index 00000000000..536f41fd48d --- /dev/null +++ b/modules/path_tracking/stanley_control/stanley_control.html @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Stanley control — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Rear wheel feedback control" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html" /> + <link rel="prev" title="Pure pursuit tracking" href="../pure_pursuit_tracking/pure_pursuit_tracking.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../path_tracking.html">Path Tracking</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../pure_pursuit_tracking/pure_pursuit_tracking.html">Pure pursuit tracking</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Stanley control</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html">Rear wheel feedback control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_steering_control/lqr_steering_control.html">Linear–quadratic regulator (LQR) steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../lqr_speed_and_steering_control/lqr_speed_and_steering_control.html">Linear–quadratic regulator (LQR) speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control.html">Model predictive speed and steering control</a></li> +<li class="toctree-l2"><a class="reference internal" href="../cgmres_nmpc/cgmres_nmpc.html">Nonlinear Model Predictive Control with C-GMRES</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../path_tracking.html">Path Tracking</a> »</li> + <li>Stanley control</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/path_tracking/stanley_control/stanley_control_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="stanley-control"> +<h1>Stanley control<a class="headerlink" href="#stanley-control" title="Permalink to this headline"></a></h1> +<p>Path tracking simulation with Stanley steering control and PID speed +control.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/stanley_controller/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/PathTracking/stanley_controller/animation.gif" /> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://robots.stanford.edu/papers/thrun.stanley05.pdf">Stanley: The robot that won the DARPA grand +challenge</a></p></li> +<li><p><a class="reference external" href="https://www.ri.cmu.edu/pub_files/2009/2/Automatic_Steering_Methods_for_Autonomous_Automobile_Path_Tracking.pdf">Automatic Steering Methods for Autonomous Automobile Path +Tracking</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../pure_pursuit_tracking/pure_pursuit_tracking.html" class="btn btn-neutral float-left" title="Pure pursuit tracking" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../rear_wheel_feedback_control/rear_wheel_feedback_control.html" class="btn btn-neutral float-right" title="Rear wheel feedback control" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/slam/FastSLAM1/FastSLAM1.html b/modules/slam/FastSLAM1/FastSLAM1.html new file mode 100644 index 00000000000..cb84afc95d2 --- /dev/null +++ b/modules/slam/FastSLAM1/FastSLAM1.html @@ -0,0 +1,649 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>FastSLAM1.0 — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="FastSLAM 2.0" href="../FastSLAM2/FastSLAM2.html" /> + <link rel="prev" title="EKF SLAM" href="../ekf_slam/ekf_slam.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../slam.html">SLAM</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ekf_slam/ekf_slam.html">EKF SLAM</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">FastSLAM1.0</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#simulation">Simulation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#introduction">Introduction</a></li> +<li class="toctree-l3"><a class="reference internal" href="#algorithm-walk-through">Algorithm walk through</a></li> +<li class="toctree-l3"><a class="reference internal" href="#predict">1- Predict</a></li> +<li class="toctree-l3"><a class="reference internal" href="#update">2- Update</a></li> +<li class="toctree-l3"><a class="reference internal" href="#resampling">3- Resampling</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="../graph_slam/graph_slam.html">Graph based SLAM</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../slam.html">SLAM</a> »</li> + <li>FastSLAM1.0</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/slam/FastSLAM1/FastSLAM1_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="fastslam1-0"> +<h1>FastSLAM1.0<a class="headerlink" href="#fastslam1-0" title="Permalink to this headline"></a></h1> +<figure class="align-default"> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/FastSLAM1/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/FastSLAM1/animation.gif" /> +</figure> +<section id="simulation"> +<h2>Simulation<a class="headerlink" href="#simulation" title="Permalink to this headline"></a></h2> +<p>This is a feature based SLAM example using FastSLAM 1.0.</p> +<a class="reference internal image-reference" href="../../../_images/FastSLAM1_1_0.png"><img alt="../../../_images/FastSLAM1_1_0.png" src="../../../_images/FastSLAM1_1_0.png" style="width: 600px;" /></a> +<p>The blue line is ground truth, the black line is dead reckoning, the red +line is the estimated trajectory with FastSLAM.</p> +<p>The red points are particles of FastSLAM.</p> +<p>Black points are landmarks, blue crosses are estimated landmark +positions by FastSLAM.</p> +</section> +<section id="introduction"> +<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h2> +<p>FastSLAM algorithm implementation is based on particle filters and +belongs to the family of probabilistic SLAM approaches. It is used with +feature-based maps (see gif above) or with occupancy grid maps.</p> +<p>As it is shown, the particle filter differs from EKF by representing the +robot’s estimation through a set of particles. Each single particle has +an independent belief, as it holds the pose <span class="math notranslate nohighlight">\((x, y, \theta)\)</span> and +an array of landmark locations +<span class="math notranslate nohighlight">\([(x_1, y_1), (x_2, y_2), ... (x_n, y_n)]\)</span> for n landmarks.</p> +<ul class="simple"> +<li><p>The blue line is the true trajectory</p></li> +<li><p>The red line is the estimated trajectory</p></li> +<li><p>The red dots represent the distribution of particles</p></li> +<li><p>The black line represent dead reckoning trajectory</p></li> +<li><p>The blue x is the observed and estimated landmarks</p></li> +<li><p>The black x is the true landmark</p></li> +</ul> +<p>I.e. Each particle maintains a deterministic pose and n-EKFs for each +landmark and update it with each measurement.</p> +</section> +<section id="algorithm-walk-through"> +<h2>Algorithm walk through<a class="headerlink" href="#algorithm-walk-through" title="Permalink to this headline"></a></h2> +<p>The particles are initially drawn from a uniform distribution the +represent the initial uncertainty. At each time step we do:</p> +<ul class="simple"> +<li><p>Predict the pose for each particle by using <span class="math notranslate nohighlight">\(u\)</span> and the motion +model (the landmarks are not updated).</p></li> +<li><p>Update the particles with observations <span class="math notranslate nohighlight">\(z\)</span>, where the weights +are adjusted based on how likely the particle to have the correct +pose given the sensor measurement</p></li> +<li><p>Resampling such that the particles with the largest weights survive +and the unlikely ones with the lowest weights die out.</p></li> +</ul> +</section> +<section id="predict"> +<h2>1- Predict<a class="headerlink" href="#predict" title="Permalink to this headline"></a></h2> +<p>The following equations and code snippets we can see how the particles +distribution evolves in case we provide only the control <span class="math notranslate nohighlight">\((v,w)\)</span>, +which are the linear and angular velocity respectively.</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} F= \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} B= \begin{bmatrix} \Delta t cos(\theta) & 0\\ \Delta t sin(\theta) & 0\\ 0 & \Delta t \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} X = FX + BU \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} \begin{bmatrix} x_{t+1} \\ y_{t+1} \\ \theta_{t+1} \end{bmatrix}= \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}\begin{bmatrix} x_{t} \\ y_{t} \\ \theta_{t} \end{bmatrix}+ \begin{bmatrix} \Delta t cos(\theta) & 0\\ \Delta t sin(\theta) & 0\\ 0 & \Delta t \end{bmatrix} \begin{bmatrix} v_{t} + \sigma_v\\ w_{t} + \sigma_w\\ \end{bmatrix} \end{equation*}\)</span></p> +<p>The following snippets playback the recorded trajectory of each +particle.</p> +<p>To get the insight of the motion model change the value of <span class="math notranslate nohighlight">\(R\)</span> and +re-run the cells again. As R is the parameters that indicates how much +we trust that the robot executed the motion commands.</p> +<p>It is interesting to notice also that only motion will increase the +uncertainty in the system as the particles start to spread out more. If +observations are included the uncertainty will decrease and particles +will converge to the correct estimate.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># CODE SNIPPET #</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="kn">from</span> <span class="nn">copy</span> <span class="kn">import</span> <span class="n">deepcopy</span> +<span class="c1"># Fast SLAM covariance</span> +<span class="n">Q</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">10.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> +<span class="n">R</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">20.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> + +<span class="c1"># Simulation parameter</span> +<span class="n">Qsim</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">2.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> +<span class="n">Rsim</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">10.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> +<span class="n">OFFSET_YAWRATE_NOISE</span> <span class="o">=</span> <span class="mf">0.01</span> + +<span class="n">DT</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="c1"># time tick [s]</span> +<span class="n">SIM_TIME</span> <span class="o">=</span> <span class="mf">50.0</span> <span class="c1"># simulation time [s]</span> +<span class="n">MAX_RANGE</span> <span class="o">=</span> <span class="mf">20.0</span> <span class="c1"># maximum observation range</span> +<span class="n">M_DIST_TH</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="c1"># Threshold of Mahalanobis distance for data association.</span> +<span class="n">STATE_SIZE</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1"># State size [x,y,yaw]</span> +<span class="n">LM_SIZE</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># LM srate size [x,y]</span> +<span class="n">N_PARTICLE</span> <span class="o">=</span> <span class="mi">100</span> <span class="c1"># number of particle</span> +<span class="n">NTH</span> <span class="o">=</span> <span class="n">N_PARTICLE</span> <span class="o">/</span> <span class="mf">1.5</span> <span class="c1"># Number of particle for re-sampling</span> + +<span class="k">class</span> <span class="nc">Particle</span><span class="p">:</span> + + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">N_LM</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">w</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="n">N_PARTICLE</span> + <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="bp">self</span><span class="o">.</span><span class="n">yaw</span> <span class="o">=</span> <span class="mf">0.0</span> + <span class="c1"># landmark x-y positions</span> + <span class="bp">self</span><span class="o">.</span><span class="n">lm</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">N_LM</span><span class="p">,</span> <span class="n">LM_SIZE</span><span class="p">))</span> + <span class="c1"># landmark position covariance</span> + <span class="bp">self</span><span class="o">.</span><span class="n">lmP</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">N_LM</span> <span class="o">*</span> <span class="n">LM_SIZE</span><span class="p">,</span> <span class="n">LM_SIZE</span><span class="p">))</span> + +<span class="k">def</span> <span class="nf">motion_model</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">u</span><span class="p">):</span> + <span class="n">F</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]])</span> + + <span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">DT</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="n">DT</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">DT</span><span class="p">]])</span> + <span class="n">x</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">x</span> <span class="o">+</span> <span class="n">B</span> <span class="o">@</span> <span class="n">u</span> + + <span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> + <span class="k">return</span> <span class="n">x</span> + +<span class="k">def</span> <span class="nf">predict_particles</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">u</span><span class="p">):</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">px</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> + <span class="n">px</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> + <span class="n">px</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">y</span> + <span class="n">px</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">yaw</span> + <span class="n">ud</span> <span class="o">=</span> <span class="n">u</span> <span class="o">+</span> <span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">@</span> <span class="n">R</span><span class="p">)</span><span class="o">.</span><span class="n">T</span> <span class="c1"># add noise</span> + <span class="n">px</span> <span class="o">=</span> <span class="n">motion_model</span><span class="p">(</span><span class="n">px</span><span class="p">,</span> <span class="n">ud</span><span class="p">)</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">px</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">px</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">yaw</span> <span class="o">=</span> <span class="n">px</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + + <span class="k">return</span> <span class="n">particles</span> + +<span class="k">def</span> <span class="nf">pi_2_pi</span><span class="p">(</span><span class="n">angle</span><span class="p">):</span> + <span class="k">return</span> <span class="p">(</span><span class="n">angle</span> <span class="o">+</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">-</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span> + +<span class="c1"># END OF SNIPPET</span> + +<span class="n">N_LM</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">particles</span> <span class="o">=</span> <span class="p">[</span><span class="n">Particle</span><span class="p">(</span><span class="n">N_LM</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">)]</span> +<span class="n">time</span><span class="o">=</span> <span class="mf">0.0</span> +<span class="n">v</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1"># [m/s]</span> +<span class="n">yawrate</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="c1"># [rad/s]</span> +<span class="n">u</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">v</span><span class="p">,</span> <span class="n">yawrate</span><span class="p">])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> +<span class="n">history</span> <span class="o">=</span> <span class="p">[]</span> +<span class="k">while</span> <span class="n">SIM_TIME</span> <span class="o">>=</span> <span class="n">time</span><span class="p">:</span> + <span class="n">time</span> <span class="o">+=</span> <span class="n">DT</span> + <span class="n">particles</span> <span class="o">=</span> <span class="n">predict_particles</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">u</span><span class="p">)</span> + <span class="n">history</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">particles</span><span class="p">))</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># from IPython.html.widgets import *</span> +<span class="kn">from</span> <span class="nn">ipywidgets</span> <span class="kn">import</span> <span class="o">*</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="o">%</span><span class="k">matplotlib</span> inline + +<span class="c1"># playback the recorded motion of the particles</span> +<span class="k">def</span> <span class="nf">plot_particles</span><span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span> + <span class="n">x</span> <span class="o">=</span> <span class="p">[]</span> + <span class="n">y</span> <span class="o">=</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">history</span><span class="p">[</span><span class="n">t</span><span class="p">])):</span> + <span class="n">x</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">history</span><span class="p">[</span><span class="n">t</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span><span class="p">)</span> + <span class="n">y</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">history</span><span class="p">[</span><span class="n">t</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">y</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">figtext</span><span class="p">(</span><span class="mf">0.15</span><span class="p">,</span><span class="mf">0.82</span><span class="p">,</span><span class="s1">'t = '</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">t</span><span class="p">))</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s1">'.r'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">([</span><span class="o">-</span><span class="mi">20</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">,</span><span class="mi">25</span><span class="p">])</span> + +<span class="n">interact</span><span class="p">(</span><span class="n">plot_particles</span><span class="p">,</span> <span class="n">t</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">history</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">));</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>interactive(children=(IntSlider(value=0, description='t', max=499), Output()), _dom_classes=('widget-interact'… +</pre></div> +</div> +</section> +<section id="update"> +<h2>2- Update<a class="headerlink" href="#update" title="Permalink to this headline"></a></h2> +<p>For the update step it is useful to observe a single particle and the +effect of getting a new measurements on the weight of the particle.</p> +<p>As mentioned earlier, each particle maintains <span class="math notranslate nohighlight">\(N\)</span> <span class="math notranslate nohighlight">\(2x2\)</span> EKFs +to estimate the landmarks, which includes the EKF process described in +the EKF notebook. The difference is the change in the weight of the +particle according to how likely the measurement is.</p> +<p>The weight is updated according to the following equation:</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} w_i = |2\pi Q|^{\frac{-1}{2}} exp\{\frac{-1}{2}(z_t - \hat z_i)^T Q^{-1}(z_t-\hat z_i)\} \end{equation*}\)</span></p> +<p>Where, <span class="math notranslate nohighlight">\(w_i\)</span> is the computed weight, <span class="math notranslate nohighlight">\(Q\)</span> is the measurement +covariance, <span class="math notranslate nohighlight">\(z_t\)</span> is the actual measurment and <span class="math notranslate nohighlight">\(\hat z_i\)</span> is +the predicted measurement of particle <span class="math notranslate nohighlight">\(i\)</span>.</p> +<p>To experiment this, a single particle is initialized then passed an +initial measurement, which results in a relatively average weight. +However, setting the particle coordinate to a wrong value to simulate +wrong estimation will result in a very low weight. The lower the weight +the less likely that this particle will be drawn during resampling and +probably will die out.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># CODE SNIPPET #</span> +<span class="k">def</span> <span class="nf">observation</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">xd</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">RFID</span><span class="p">):</span> + + <span class="c1"># calc true state</span> + <span class="n">xTrue</span> <span class="o">=</span> <span class="n">motion_model</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">u</span><span class="p">)</span> + + <span class="c1"># add noise to range observation</span> + <span class="n">z</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">RFID</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])):</span> + + <span class="n">dx</span> <span class="o">=</span> <span class="n">RFID</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">xTrue</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">dy</span> <span class="o">=</span> <span class="n">RFID</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">xTrue</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">dx</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">dy</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> + <span class="n">angle</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">atan2</span><span class="p">(</span><span class="n">dy</span><span class="p">,</span> <span class="n">dx</span><span class="p">)</span> <span class="o">-</span> <span class="n">xTrue</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> + <span class="k">if</span> <span class="n">d</span> <span class="o"><=</span> <span class="n">MAX_RANGE</span><span class="p">:</span> + <span class="n">dn</span> <span class="o">=</span> <span class="n">d</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Qsim</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="c1"># add noise</span> + <span class="n">anglen</span> <span class="o">=</span> <span class="n">angle</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Qsim</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="c1"># add noise</span> + <span class="n">zi</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">dn</span><span class="p">,</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">anglen</span><span class="p">),</span> <span class="n">i</span><span class="p">])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + <span class="n">z</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">z</span><span class="p">,</span> <span class="n">zi</span><span class="p">))</span> + + <span class="c1"># add noise to input</span> + <span class="n">ud1</span> <span class="o">=</span> <span class="n">u</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Rsim</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">ud2</span> <span class="o">=</span> <span class="n">u</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Rsim</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">OFFSET_YAWRATE_NOISE</span> + <span class="n">ud</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">ud1</span><span class="p">,</span> <span class="n">ud2</span><span class="p">])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + + <span class="n">xd</span> <span class="o">=</span> <span class="n">motion_model</span><span class="p">(</span><span class="n">xd</span><span class="p">,</span> <span class="n">ud</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">xTrue</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">xd</span><span class="p">,</span> <span class="n">ud</span> + +<span class="k">def</span> <span class="nf">update_with_observation</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">z</span><span class="p">):</span> + <span class="k">for</span> <span class="n">iz</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:])):</span> + + <span class="n">lmid</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">z</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="n">iz</span><span class="p">])</span> + + <span class="k">for</span> <span class="n">ip</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="c1"># new landmark</span> + <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">]</span><span class="o">.</span><span class="n">lm</span><span class="p">[</span><span class="n">lmid</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o"><=</span> <span class="mf">0.01</span><span class="p">:</span> + <span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">]</span> <span class="o">=</span> <span class="n">add_new_lm</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">],</span> <span class="n">z</span><span class="p">[:,</span> <span class="n">iz</span><span class="p">],</span> <span class="n">Q</span><span class="p">)</span> + <span class="c1"># known landmark</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">w</span> <span class="o">=</span> <span class="n">compute_weight</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">],</span> <span class="n">z</span><span class="p">[:,</span> <span class="n">iz</span><span class="p">],</span> <span class="n">Q</span><span class="p">)</span> + <span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">]</span><span class="o">.</span><span class="n">w</span> <span class="o">*=</span> <span class="n">w</span> + <span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">]</span> <span class="o">=</span> <span class="n">update_landmark</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">ip</span><span class="p">],</span> <span class="n">z</span><span class="p">[:,</span> <span class="n">iz</span><span class="p">],</span> <span class="n">Q</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">particles</span> + +<span class="k">def</span> <span class="nf">compute_weight</span><span class="p">(</span><span class="n">particle</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">Q</span><span class="p">):</span> + <span class="n">lm_id</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">z</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> + <span class="n">xf</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">particle</span><span class="o">.</span><span class="n">lm</span><span class="p">[</span><span class="n">lm_id</span><span class="p">,</span> <span class="p">:])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + <span class="n">Pf</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">particle</span><span class="o">.</span><span class="n">lmP</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span><span class="p">:</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span> <span class="o">+</span> <span class="mi">2</span><span class="p">])</span> + <span class="n">zp</span><span class="p">,</span> <span class="n">Hv</span><span class="p">,</span> <span class="n">Hf</span><span class="p">,</span> <span class="n">Sf</span> <span class="o">=</span> <span class="n">compute_jacobians</span><span class="p">(</span><span class="n">particle</span><span class="p">,</span> <span class="n">xf</span><span class="p">,</span> <span class="n">Pf</span><span class="p">,</span> <span class="n">Q</span><span class="p">)</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">zp</span> + <span class="n">dx</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">dx</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> + + <span class="k">try</span><span class="p">:</span> + <span class="n">invS</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">Sf</span><span class="p">)</span> + <span class="k">except</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">LinAlgError</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"singuler"</span><span class="p">)</span> + <span class="k">return</span> <span class="mf">1.0</span> + + <span class="n">num</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">dx</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">invS</span> <span class="o">@</span> <span class="n">dx</span><span class="p">)</span> + <span class="n">den</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">det</span><span class="p">(</span><span class="n">Sf</span><span class="p">))</span> + <span class="n">w</span> <span class="o">=</span> <span class="n">num</span> <span class="o">/</span> <span class="n">den</span> + + <span class="k">return</span> <span class="n">w</span> + +<span class="k">def</span> <span class="nf">compute_jacobians</span><span class="p">(</span><span class="n">particle</span><span class="p">,</span> <span class="n">xf</span><span class="p">,</span> <span class="n">Pf</span><span class="p">,</span> <span class="n">Q</span><span class="p">):</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">xf</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">particle</span><span class="o">.</span><span class="n">x</span> + <span class="n">dy</span> <span class="o">=</span> <span class="n">xf</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">particle</span><span class="o">.</span><span class="n">y</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">dx</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">dy</span><span class="o">**</span><span class="mi">2</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">d2</span><span class="p">)</span> + + <span class="n">zp</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="p">[</span><span class="n">d</span><span class="p">,</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">atan2</span><span class="p">(</span><span class="n">dy</span><span class="p">,</span> <span class="n">dx</span><span class="p">)</span> <span class="o">-</span> <span class="n">particle</span><span class="o">.</span><span class="n">yaw</span><span class="p">)])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + + <span class="n">Hv</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="o">-</span><span class="n">dx</span> <span class="o">/</span> <span class="n">d</span><span class="p">,</span> <span class="o">-</span><span class="n">dy</span> <span class="o">/</span> <span class="n">d</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">],</span> + <span class="p">[</span><span class="n">dy</span> <span class="o">/</span> <span class="n">d2</span><span class="p">,</span> <span class="o">-</span><span class="n">dx</span> <span class="o">/</span> <span class="n">d2</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">]])</span> + + <span class="n">Hf</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">dx</span> <span class="o">/</span> <span class="n">d</span><span class="p">,</span> <span class="n">dy</span> <span class="o">/</span> <span class="n">d</span><span class="p">],</span> + <span class="p">[</span><span class="o">-</span><span class="n">dy</span> <span class="o">/</span> <span class="n">d2</span><span class="p">,</span> <span class="n">dx</span> <span class="o">/</span> <span class="n">d2</span><span class="p">]])</span> + + <span class="n">Sf</span> <span class="o">=</span> <span class="n">Hf</span> <span class="o">@</span> <span class="n">Pf</span> <span class="o">@</span> <span class="n">Hf</span><span class="o">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">Q</span> + + <span class="k">return</span> <span class="n">zp</span><span class="p">,</span> <span class="n">Hv</span><span class="p">,</span> <span class="n">Hf</span><span class="p">,</span> <span class="n">Sf</span> + +<span class="k">def</span> <span class="nf">add_new_lm</span><span class="p">(</span><span class="n">particle</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">Q</span><span class="p">):</span> + + <span class="n">r</span> <span class="o">=</span> <span class="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">z</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> + <span class="n">lm_id</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">z</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> + + <span class="n">s</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">pi_2_pi</span><span class="p">(</span><span class="n">particle</span><span class="o">.</span><span class="n">yaw</span> <span class="o">+</span> <span class="n">b</span><span class="p">))</span> + <span class="n">c</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">pi_2_pi</span><span class="p">(</span><span class="n">particle</span><span class="o">.</span><span class="n">yaw</span> <span class="o">+</span> <span class="n">b</span><span class="p">))</span> + + <span class="n">particle</span><span class="o">.</span><span class="n">lm</span><span class="p">[</span><span class="n">lm_id</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">particle</span><span class="o">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">r</span> <span class="o">*</span> <span class="n">c</span> + <span class="n">particle</span><span class="o">.</span><span class="n">lm</span><span class="p">[</span><span class="n">lm_id</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">particle</span><span class="o">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">r</span> <span class="o">*</span> <span class="n">s</span> + + <span class="c1"># covariance</span> + <span class="n">Gz</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">c</span><span class="p">,</span> <span class="o">-</span><span class="n">r</span> <span class="o">*</span> <span class="n">s</span><span class="p">],</span> + <span class="p">[</span><span class="n">s</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span> <span class="n">c</span><span class="p">]])</span> + + <span class="n">particle</span><span class="o">.</span><span class="n">lmP</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span><span class="p">:</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">Gz</span> <span class="o">@</span> <span class="n">Q</span> <span class="o">@</span> <span class="n">Gz</span><span class="o">.</span><span class="n">T</span> + + <span class="k">return</span> <span class="n">particle</span> + +<span class="k">def</span> <span class="nf">update_KF_with_cholesky</span><span class="p">(</span><span class="n">xf</span><span class="p">,</span> <span class="n">Pf</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">Q</span><span class="p">,</span> <span class="n">Hf</span><span class="p">):</span> + <span class="n">PHt</span> <span class="o">=</span> <span class="n">Pf</span> <span class="o">@</span> <span class="n">Hf</span><span class="o">.</span><span class="n">T</span> + <span class="n">S</span> <span class="o">=</span> <span class="n">Hf</span> <span class="o">@</span> <span class="n">PHt</span> <span class="o">+</span> <span class="n">Q</span> + + <span class="n">S</span> <span class="o">=</span> <span class="p">(</span><span class="n">S</span> <span class="o">+</span> <span class="n">S</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.5</span> + <span class="n">SChol</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">cholesky</span><span class="p">(</span><span class="n">S</span><span class="p">)</span><span class="o">.</span><span class="n">T</span> + <span class="n">SCholInv</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">SChol</span><span class="p">)</span> + <span class="n">W1</span> <span class="o">=</span> <span class="n">PHt</span> <span class="o">@</span> <span class="n">SCholInv</span> + <span class="n">W</span> <span class="o">=</span> <span class="n">W1</span> <span class="o">@</span> <span class="n">SCholInv</span><span class="o">.</span><span class="n">T</span> + + <span class="n">x</span> <span class="o">=</span> <span class="n">xf</span> <span class="o">+</span> <span class="n">W</span> <span class="o">@</span> <span class="n">v</span> + <span class="n">P</span> <span class="o">=</span> <span class="n">Pf</span> <span class="o">-</span> <span class="n">W1</span> <span class="o">@</span> <span class="n">W1</span><span class="o">.</span><span class="n">T</span> + + <span class="k">return</span> <span class="n">x</span><span class="p">,</span> <span class="n">P</span> + +<span class="k">def</span> <span class="nf">update_landmark</span><span class="p">(</span><span class="n">particle</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">Q</span><span class="p">):</span> + + <span class="n">lm_id</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">z</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> + <span class="n">xf</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">particle</span><span class="o">.</span><span class="n">lm</span><span class="p">[</span><span class="n">lm_id</span><span class="p">,</span> <span class="p">:])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + <span class="n">Pf</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">particle</span><span class="o">.</span><span class="n">lmP</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span><span class="p">:</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="p">:])</span> + + <span class="n">zp</span><span class="p">,</span> <span class="n">Hv</span><span class="p">,</span> <span class="n">Hf</span><span class="p">,</span> <span class="n">Sf</span> <span class="o">=</span> <span class="n">compute_jacobians</span><span class="p">(</span><span class="n">particle</span><span class="p">,</span> <span class="n">xf</span><span class="p">,</span> <span class="n">Pf</span><span class="p">,</span> <span class="n">Q</span><span class="p">)</span> + + <span class="n">dz</span> <span class="o">=</span> <span class="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">zp</span> + <span class="n">dz</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">dz</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> + + <span class="n">xf</span><span class="p">,</span> <span class="n">Pf</span> <span class="o">=</span> <span class="n">update_KF_with_cholesky</span><span class="p">(</span><span class="n">xf</span><span class="p">,</span> <span class="n">Pf</span><span class="p">,</span> <span class="n">dz</span><span class="p">,</span> <span class="n">Q</span><span class="p">,</span> <span class="n">Hf</span><span class="p">)</span> + + <span class="n">particle</span><span class="o">.</span><span class="n">lm</span><span class="p">[</span><span class="n">lm_id</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">xf</span><span class="o">.</span><span class="n">T</span> + <span class="n">particle</span><span class="o">.</span><span class="n">lmP</span><span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span><span class="p">:</span><span class="mi">2</span> <span class="o">*</span> <span class="n">lm_id</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">Pf</span> + + <span class="k">return</span> <span class="n">particle</span> + +<span class="c1"># END OF CODE SNIPPET #</span> + + + +<span class="c1"># Setting up the landmarks</span> +<span class="n">RFID</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">10.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">],</span> + <span class="p">[</span><span class="mf">15.0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">]])</span> +<span class="n">N_LM</span> <span class="o">=</span> <span class="n">RFID</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> + +<span class="c1"># Initialize 1 particle</span> +<span class="n">N_PARTICLE</span> <span class="o">=</span> <span class="mi">1</span> +<span class="n">particles</span> <span class="o">=</span> <span class="p">[</span><span class="n">Particle</span><span class="p">(</span><span class="n">N_LM</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">)]</span> + +<span class="n">xTrue</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> +<span class="n">xDR</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> + +<span class="nb">print</span><span class="p">(</span><span class="s2">"initial weight"</span><span class="p">,</span> <span class="n">particles</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">w</span><span class="p">)</span> + +<span class="n">xTrue</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">ud</span> <span class="o">=</span> <span class="n">observation</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">xDR</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">RFID</span><span class="p">)</span> +<span class="c1"># Initialize landmarks</span> +<span class="n">particles</span> <span class="o">=</span> <span class="n">update_with_observation</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"weight after landmark intialization"</span><span class="p">,</span> <span class="n">particles</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">w</span><span class="p">)</span> +<span class="n">particles</span> <span class="o">=</span> <span class="n">update_with_observation</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"weight after update "</span><span class="p">,</span> <span class="n">particles</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">w</span><span class="p">)</span> + +<span class="n">particles</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="o">-</span><span class="mi">10</span> +<span class="n">particles</span> <span class="o">=</span> <span class="n">update_with_observation</span><span class="p">(</span><span class="n">particles</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"weight after wrong prediction"</span><span class="p">,</span> <span class="n">particles</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">w</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">initial</span> <span class="n">weight</span> <span class="mf">1.0</span> +<span class="n">weight</span> <span class="n">after</span> <span class="n">landmark</span> <span class="n">intialization</span> <span class="mf">1.0</span> +<span class="n">weight</span> <span class="n">after</span> <span class="n">update</span> <span class="mf">0.023098460073039763</span> +<span class="n">weight</span> <span class="n">after</span> <span class="n">wrong</span> <span class="n">prediction</span> <span class="mf">7.951154575772496e-07</span> +</pre></div> +</div> +</section> +<section id="resampling"> +<h2>3- Resampling<a class="headerlink" href="#resampling" title="Permalink to this headline"></a></h2> +<p>In the reseampling steps a new set of particles are chosen from the old +set. This is done according to the weight of each particle.</p> +<p>The figure shows 100 particles distributed uniformly between [-0.5, 0.5] +with the weights of each particle distributed according to a Gaussian +funciton.</p> +<p>The resampling picks</p> +<p><span class="math notranslate nohighlight">\(i \in 1,...,N\)</span> particles with probability to pick particle with +index <span class="math notranslate nohighlight">\(i ∝ \omega_i\)</span>, where <span class="math notranslate nohighlight">\(\omega_i\)</span> is the weight of that +particle</p> +<p>To get the intuition of the resampling step we will look at a set of +particles which are initialized with a given x location and weight. +After the resampling the particles are more concetrated in the location +where they had the highest weights. This is also indicated by the +indices</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># CODE SNIPPET #</span> +<span class="k">def</span> <span class="nf">normalize_weight</span><span class="p">(</span><span class="n">particles</span><span class="p">):</span> + + <span class="n">sumw</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">([</span><span class="n">p</span><span class="o">.</span><span class="n">w</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">particles</span><span class="p">])</span> + + <span class="k">try</span><span class="p">:</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">w</span> <span class="o">/=</span> <span class="n">sumw</span> + <span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">w</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="n">N_PARTICLE</span> + + <span class="k">return</span> <span class="n">particles</span> + + <span class="k">return</span> <span class="n">particles</span> + + +<span class="k">def</span> <span class="nf">resampling</span><span class="p">(</span><span class="n">particles</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> low variance re-sampling</span> +<span class="sd"> """</span> + + <span class="n">particles</span> <span class="o">=</span> <span class="n">normalize_weight</span><span class="p">(</span><span class="n">particles</span><span class="p">)</span> + + <span class="n">pw</span> <span class="o">=</span> <span class="p">[]</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">pw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">w</span><span class="p">)</span> + + <span class="n">pw</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">pw</span><span class="p">)</span> + + <span class="n">Neff</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="p">(</span><span class="n">pw</span> <span class="o">@</span> <span class="n">pw</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Effective particle number</span> + <span class="c1"># print(Neff)</span> + + <span class="k">if</span> <span class="n">Neff</span> <span class="o"><</span> <span class="n">NTH</span><span class="p">:</span> <span class="c1"># resampling</span> + <span class="n">wcum</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">pw</span><span class="p">)</span> + <span class="n">base</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">pw</span> <span class="o">*</span> <span class="mf">0.0</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">N_PARTICLE</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">N_PARTICLE</span> + <span class="n">resampleid</span> <span class="o">=</span> <span class="n">base</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="n">base</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="n">N_PARTICLE</span> + + <span class="n">inds</span> <span class="o">=</span> <span class="p">[]</span> + <span class="n">ind</span> <span class="o">=</span> <span class="mi">0</span> + <span class="k">for</span> <span class="n">ip</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="k">while</span> <span class="p">((</span><span class="n">ind</span> <span class="o"><</span> <span class="n">wcum</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">resampleid</span><span class="p">[</span><span class="n">ip</span><span class="p">]</span> <span class="o">></span> <span class="n">wcum</span><span class="p">[</span><span class="n">ind</span><span class="p">])):</span> + <span class="n">ind</span> <span class="o">+=</span> <span class="mi">1</span> + <span class="n">inds</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ind</span><span class="p">)</span> + + <span class="n">tparticles</span> <span class="o">=</span> <span class="n">particles</span><span class="p">[:]</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">inds</span><span class="p">)):</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">tparticles</span><span class="p">[</span><span class="n">inds</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">.</span><span class="n">x</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">tparticles</span><span class="p">[</span><span class="n">inds</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">.</span><span class="n">y</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">yaw</span> <span class="o">=</span> <span class="n">tparticles</span><span class="p">[</span><span class="n">inds</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">.</span><span class="n">yaw</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">w</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">/</span> <span class="n">N_PARTICLE</span> + + <span class="k">return</span> <span class="n">particles</span><span class="p">,</span> <span class="n">inds</span> +<span class="c1"># END OF SNIPPET #</span> + + + +<span class="k">def</span> <span class="nf">gaussian</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">mu</span><span class="p">,</span> <span class="n">sig</span><span class="p">):</span> + <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">power</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">mu</span><span class="p">,</span> <span class="mf">2.</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">power</span><span class="p">(</span><span class="n">sig</span><span class="p">,</span> <span class="mf">2.</span><span class="p">)))</span> +<span class="n">N_PARTICLE</span> <span class="o">=</span> <span class="mi">100</span> +<span class="n">particles</span> <span class="o">=</span> <span class="p">[</span><span class="n">Particle</span><span class="p">(</span><span class="n">N_LM</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">)]</span> +<span class="n">x_pos</span> <span class="o">=</span> <span class="p">[]</span> +<span class="n">w</span> <span class="o">=</span> <span class="p">[]</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span><span class="mf">0.5</span><span class="p">,</span><span class="n">N_PARTICLE</span><span class="p">)[</span><span class="n">i</span><span class="p">]</span> + <span class="n">x_pos</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span><span class="p">)</span> + <span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">w</span> <span class="o">=</span> <span class="n">gaussian</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">N_PARTICLE</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">N_PARTICLE</span><span class="o">/</span><span class="mi">20</span><span class="p">)</span> + <span class="n">w</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">w</span><span class="p">)</span> + + +<span class="c1"># Normalize weights</span> +<span class="n">sw</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">w</span><span class="p">)</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">/=</span> <span class="n">sw</span> + +<span class="n">particles</span><span class="p">,</span> <span class="n">new_indices</span> <span class="o">=</span> <span class="n">resampling</span><span class="p">(</span><span class="n">particles</span><span class="p">)</span> +<span class="n">x_pos2</span> <span class="o">=</span> <span class="p">[]</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N_PARTICLE</span><span class="p">):</span> + <span class="n">x_pos2</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">particles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span><span class="p">)</span> + +<span class="c1"># Plot results</span> +<span class="n">fig</span><span class="p">,</span> <span class="p">((</span><span class="n">ax1</span><span class="p">,</span><span class="n">ax2</span><span class="p">,</span><span class="n">ax3</span><span class="p">))</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">nrows</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">ncols</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> +<span class="n">fig</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> +<span class="n">ax1</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x_pos</span><span class="p">,</span><span class="n">np</span><span class="o">.</span><span class="n">ones</span><span class="p">((</span><span class="n">N_PARTICLE</span><span class="p">,</span><span class="mi">1</span><span class="p">)),</span> <span class="s1">'.r'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> +<span class="n">ax1</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s2">"Particles before resampling"</span><span class="p">)</span> +<span class="n">ax1</span><span class="o">.</span><span class="n">axis</span><span class="p">((</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> +<span class="n">ax2</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">w</span><span class="p">)</span> +<span class="n">ax2</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s2">"Weights distribution"</span><span class="p">)</span> +<span class="n">ax3</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x_pos2</span><span class="p">,</span><span class="n">np</span><span class="o">.</span><span class="n">ones</span><span class="p">((</span><span class="n">N_PARTICLE</span><span class="p">,</span><span class="mi">1</span><span class="p">)),</span> <span class="s1">'.r'</span><span class="p">)</span> +<span class="n">ax3</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s2">"Particles after resampling"</span><span class="p">)</span> +<span class="n">ax3</span><span class="o">.</span><span class="n">axis</span><span class="p">((</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> +<span class="n">fig</span><span class="o">.</span><span class="n">subplots_adjust</span><span class="p">(</span><span class="n">hspace</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">hist</span><span class="p">(</span><span class="n">new_indices</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Particles indices to be resampled"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"# of time index is used"</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/FastSLAM1_12_0.png" src="../../../_images/FastSLAM1_12_0.png" /> +<img alt="../../../_images/FastSLAM1_12_1.png" src="../../../_images/FastSLAM1_12_1.png" /> +</section> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.probabilistic-robotics.org/">PROBABILISTIC ROBOTICS</a></p></li> +<li><p><a class="reference external" href="http://ais.informatik.uni-freiburg.de/teaching/ws12/mapping/pdf/slam10-fastslam.pdf">FastSLAM Lecture</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../ekf_slam/ekf_slam.html" class="btn btn-neutral float-left" title="EKF SLAM" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../FastSLAM2/FastSLAM2.html" class="btn btn-neutral float-right" title="FastSLAM 2.0" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/slam/FastSLAM2/FastSLAM2.html b/modules/slam/FastSLAM2/FastSLAM2.html new file mode 100644 index 00000000000..7c1359bb7b4 --- /dev/null +++ b/modules/slam/FastSLAM2/FastSLAM2.html @@ -0,0 +1,162 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>FastSLAM 2.0 — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Graph based SLAM" href="../graph_slam/graph_slam.html" /> + <link rel="prev" title="FastSLAM1.0" href="../FastSLAM1/FastSLAM1.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../slam.html">SLAM</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ekf_slam/ekf_slam.html">EKF SLAM</a></li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM1/FastSLAM1.html">FastSLAM1.0</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">FastSLAM 2.0</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../graph_slam/graph_slam.html">Graph based SLAM</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../slam.html">SLAM</a> »</li> + <li>FastSLAM 2.0</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/slam/FastSLAM2/FastSLAM2_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="fastslam-2-0"> +<h1>FastSLAM 2.0<a class="headerlink" href="#fastslam-2-0" title="Permalink to this headline"></a></h1> +<p>This is a feature based SLAM example using FastSLAM 2.0.</p> +<p>The animation has the same meanings as one of FastSLAM 1.0.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/FastSLAM2/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/FastSLAM2/animation.gif" /> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.probabilistic-robotics.org/">PROBABILISTIC ROBOTICS</a></p></li> +<li><p><a class="reference external" href="http://www-personal.acfr.usyd.edu.au/tbailey/software/slam_simulations.htm">SLAM simulations by Tim Bailey</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../FastSLAM1/FastSLAM1.html" class="btn btn-neutral float-left" title="FastSLAM1.0" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../graph_slam/graph_slam.html" class="btn btn-neutral float-right" title="Graph based SLAM" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/slam/ekf_slam/ekf_slam.html b/modules/slam/ekf_slam/ekf_slam.html new file mode 100644 index 00000000000..98cb6aa92ae --- /dev/null +++ b/modules/slam/ekf_slam/ekf_slam.html @@ -0,0 +1,685 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>EKF SLAM — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="FastSLAM1.0" href="../FastSLAM1/FastSLAM1.html" /> + <link rel="prev" title="Iterative Closest Point (ICP) Matching" href="../iterative_closest_point_matching/iterative_closest_point_matching.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../slam.html">SLAM</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">EKF SLAM</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#simulation">Simulation</a></li> +<li class="toctree-l3"><a class="reference internal" href="#introduction">Introduction</a></li> +<li class="toctree-l3"><a class="reference internal" href="#algorithm-walk-through">Algorithm Walk through</a></li> +<li class="toctree-l3"><a class="reference internal" href="#predict">1- Predict</a></li> +<li class="toctree-l3"><a class="reference internal" href="#update">2 - Update</a></li> +<li class="toctree-l3"><a class="reference internal" href="#observation-step">Observation Step</a></li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM1/FastSLAM1.html">FastSLAM1.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="../graph_slam/graph_slam.html">Graph based SLAM</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../slam.html">SLAM</a> »</li> + <li>EKF SLAM</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/slam/ekf_slam/ekf_slam_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="ekf-slam"> +<h1>EKF SLAM<a class="headerlink" href="#ekf-slam" title="Permalink to this headline"></a></h1> +<p>This is an Extended Kalman Filter based SLAM example.</p> +<p>The blue line is ground truth, the black line is dead reckoning, the red +line is the estimated trajectory with EKF SLAM.</p> +<p>The green crosses are estimated landmarks.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/EKFSLAM/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/EKFSLAM/animation.gif" /> +<section id="simulation"> +<h2>Simulation<a class="headerlink" href="#simulation" title="Permalink to this headline"></a></h2> +<p>This is a simulation of EKF SLAM.</p> +<ul class="simple"> +<li><p>Black stars: landmarks</p></li> +<li><p>Green crosses: estimates of landmark positions</p></li> +<li><p>Black line: dead reckoning</p></li> +<li><p>Blue line: ground truth</p></li> +<li><p>Red line: EKF SLAM position estimation</p></li> +</ul> +</section> +<section id="introduction"> +<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h2> +<p>EKF SLAM models the SLAM problem in a single EKF where the modeled state +is both the pose <span class="math notranslate nohighlight">\((x, y, \theta)\)</span> and an array of landmarks +<span class="math notranslate nohighlight">\([(x_1, y_1), (x_2, x_y), ... , (x_n, y_n)]\)</span> for <span class="math notranslate nohighlight">\(n\)</span> +landmarks. The covariance between each of the positions and landmarks +are also tracked.</p> +<p><span class="math notranslate nohighlight">\(\begin{equation} X = \begin{bmatrix} x \\ y \\ \theta \\ x_1 \\ y_1 \\ x_2 \\ y_2 \\ \dots \\ x_n \\ y_n \end{bmatrix} \end{equation}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation} P = \begin{bmatrix} \sigma_{xx} & \sigma_{xy} & \sigma_{x\theta} & \sigma_{xx_1} & \sigma_{xy_1} & \sigma_{xx_2} & \sigma_{xy_2} & \dots & \sigma_{xx_n} & \sigma_{xy_n} \\ \sigma_{yx} & \sigma_{yy} & \sigma_{y\theta} & \sigma_{yx_1} & \sigma_{yy_1} & \sigma_{yx_2} & \sigma_{yy_2} & \dots & \sigma_{yx_n} & \sigma_{yy_n} \\ & & & & \vdots & & & & & \\ \sigma_{x_nx} & \sigma_{x_ny} & \sigma_{x_n\theta} & \sigma_{x_nx_1} & \sigma_{x_ny_1} & \sigma_{x_nx_2} & \sigma_{x_ny_2} & \dots & \sigma_{x_nx_n} & \sigma_{x_ny_n} \end{bmatrix} \end{equation}\)</span></p> +<p>A single estimate of the pose is tracked over time, while the confidence +in the pose is tracked by the covariance matrix <span class="math notranslate nohighlight">\(P\)</span>. <span class="math notranslate nohighlight">\(P\)</span> is +a symmetric square matrix which each element in the matrix corresponding +to the covariance between two parts of the system. For example, +<span class="math notranslate nohighlight">\(\sigma_{xy}\)</span> represents the covariance between the belief of +<span class="math notranslate nohighlight">\(x\)</span> and <span class="math notranslate nohighlight">\(y\)</span> and is equal to <span class="math notranslate nohighlight">\(\sigma_{yx}\)</span>.</p> +<p>The state can be represented more concisely as follows.</p> +<p><span class="math notranslate nohighlight">\(\begin{equation} X = \begin{bmatrix} x \\ m \end{bmatrix} \end{equation}\)</span> +<span class="math notranslate nohighlight">\(\begin{equation} P = \begin{bmatrix} \Sigma_{xx} & \Sigma_{xm}\\ \Sigma_{mx} & \Sigma_{mm}\\ \end{bmatrix} \end{equation}\)</span></p> +<p>Here the state simplifies to a combination of pose (<span class="math notranslate nohighlight">\(x\)</span>) and map +(<span class="math notranslate nohighlight">\(m\)</span>). The covariance matrix becomes easier to understand and +simply reads as the uncertainty of the robots pose +(<span class="math notranslate nohighlight">\(\Sigma_{xx}\)</span>), the uncertainty of the map (<span class="math notranslate nohighlight">\(\Sigma_{mm}\)</span>), +and the uncertainty of the robots pose with respect to the map and vice +versa (<span class="math notranslate nohighlight">\(\Sigma_{xm}\)</span>, <span class="math notranslate nohighlight">\(\Sigma_{mx}\)</span>).</p> +<p>Take care to note the difference between <span class="math notranslate nohighlight">\(X\)</span> (state) and <span class="math notranslate nohighlight">\(x\)</span> +(pose).</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="sd">"""</span> +<span class="sd">Extended Kalman Filter SLAM example</span> +<span class="sd">original author: Atsushi Sakai (@Atsushi_twi)</span> +<span class="sd">notebook author: Andrew Tu (drewtu2)</span> +<span class="sd">"""</span> + +<span class="kn">import</span> <span class="nn">math</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="o">%</span><span class="k">matplotlib</span> notebook +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> + + +<span class="c1"># EKF state covariance</span> +<span class="n">Cx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">30.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> <span class="c1"># Change in covariance</span> + +<span class="c1"># Simulation parameter</span> +<span class="n">Qsim</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">0.2</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> <span class="c1"># Sensor Noise</span> +<span class="n">Rsim</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">10.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> <span class="c1"># Process Noise</span> + +<span class="n">DT</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="c1"># time tick [s]</span> +<span class="n">SIM_TIME</span> <span class="o">=</span> <span class="mf">50.0</span> <span class="c1"># simulation time [s]</span> +<span class="n">MAX_RANGE</span> <span class="o">=</span> <span class="mf">20.0</span> <span class="c1"># maximum observation range</span> +<span class="n">M_DIST_TH</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="c1"># Threshold of Mahalanobis distance for data association.</span> +<span class="n">STATE_SIZE</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1"># State size [x,y,yaw]</span> +<span class="n">LM_SIZE</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># LM state size [x,y]</span> + +<span class="n">show_animation</span> <span class="o">=</span> <span class="kc">True</span> +</pre></div> +</div> +</section> +<section id="algorithm-walk-through"> +<h2>Algorithm Walk through<a class="headerlink" href="#algorithm-walk-through" title="Permalink to this headline"></a></h2> +<p>At each time step, the following is done. - predict the new state using +the control functions - update the belief in landmark positions based on +the estimated state and measurements</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">ekf_slam</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">z</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Performs an iteration of EKF SLAM from the available information.</span> + +<span class="sd"> :param xEst: the belief in last position</span> +<span class="sd"> :param PEst: the uncertainty in last position</span> +<span class="sd"> :param u: the control function applied to the last position</span> +<span class="sd"> :param z: measurements at this step</span> +<span class="sd"> :returns: the next estimated position and associated covariance</span> +<span class="sd"> """</span> + <span class="n">S</span> <span class="o">=</span> <span class="n">STATE_SIZE</span> + + <span class="c1"># Predict</span> + <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">G</span><span class="p">,</span> <span class="n">Fx</span> <span class="o">=</span> <span class="n">predict</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">u</span><span class="p">)</span> + <span class="n">initP</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> + + <span class="c1"># Update</span> + <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">initP</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span> +</pre></div> +</div> +</section> +<section id="predict"> +<h2>1- Predict<a class="headerlink" href="#predict" title="Permalink to this headline"></a></h2> +<p><strong>Predict State update:</strong> The following equations describe the predicted +motion model of the robot in case we provide only the control +<span class="math notranslate nohighlight">\((v,w)\)</span>, which are the linear and angular velocity respectively.</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} F= \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} B= \begin{bmatrix} \Delta t cos(\theta) & 0\\ \Delta t sin(\theta) & 0\\ 0 & \Delta t \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} U= \begin{bmatrix} v_t\\ w_t\\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} X = FX + BU \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} \begin{bmatrix} x_{t+1} \\ y_{t+1} \\ \theta_{t+1} \end{bmatrix}= \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}\begin{bmatrix} x_{t} \\ y_{t} \\ \theta_{t} \end{bmatrix}+ \begin{bmatrix} \Delta t cos(\theta) & 0\\ \Delta t sin(\theta) & 0\\ 0 & \Delta t \end{bmatrix} \begin{bmatrix} v_{t} + \sigma_v\\ w_{t} + \sigma_w\\ \end{bmatrix} \end{equation*}\)</span></p> +<p>Notice that while <span class="math notranslate nohighlight">\(U\)</span> is only defined by <span class="math notranslate nohighlight">\(v_t\)</span> and +<span class="math notranslate nohighlight">\(w_t\)</span>, in the actual calculations, a <span class="math notranslate nohighlight">\(+\sigma_v\)</span> and +<span class="math notranslate nohighlight">\(+\sigma_w\)</span> appear. These values represent the error between the +given control inputs and the actual control inputs.</p> +<p>As a result, the simulation is set up as the following. <span class="math notranslate nohighlight">\(R\)</span> +represents the process noise which is added to the control inputs to +simulate noise experienced in the real world. A set of truth values are +computed from the raw control values while the values dead reckoning +values incorporate the error into the estimation.</p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} R= \begin{bmatrix} \sigma_v\\ \sigma_w\\ \end{bmatrix} \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} X_{true} = FX + B(U) \end{equation*}\)</span></p> +<p><span class="math notranslate nohighlight">\(\begin{equation*} X_{DR} = FX + B(U + R) \end{equation*}\)</span></p> +<p>The implementation of the motion model prediction code is shown in +<code class="docutils literal notranslate"><span class="pre">motion_model</span></code>. The <code class="docutils literal notranslate"><span class="pre">observation</span></code> function shows how the simulation +uses (or doesn’t use) the process noise <code class="docutils literal notranslate"><span class="pre">Rsim</span></code> to the find the ground +truth and dead reckoning estimates of the pose.</p> +<p><strong>Predict covariance:</strong> Add the state covariance to the the current +uncertainty of the EKF. At each time step, the uncertainty in the system +grows by the covariance of the pose, <span class="math notranslate nohighlight">\(Cx\)</span>.</p> +<p><span class="math notranslate nohighlight">\(P = G^TPG + Cx\)</span></p> +<p>Notice this uncertainty is only growing with respect to the pose, not +the landmarks.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">u</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Performs the prediction step of EKF SLAM</span> + +<span class="sd"> :param xEst: nx1 state vector</span> +<span class="sd"> :param PEst: nxn covariance matrix</span> +<span class="sd"> :param u: 2x1 control vector</span> +<span class="sd"> :returns: predicted state vector, predicted covariance, jacobian of control vector, transition fx</span> +<span class="sd"> """</span> + <span class="n">S</span> <span class="o">=</span> <span class="n">STATE_SIZE</span> + <span class="n">G</span><span class="p">,</span> <span class="n">Fx</span> <span class="o">=</span> <span class="n">jacob_motion</span><span class="p">(</span><span class="n">xEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">],</span> <span class="n">u</span><span class="p">)</span> + <span class="n">xEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">]</span> <span class="o">=</span> <span class="n">motion_model</span><span class="p">(</span><span class="n">xEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">],</span> <span class="n">u</span><span class="p">)</span> + <span class="c1"># Fx is an an identity matrix of size (STATE_SIZE)</span> + <span class="c1"># sigma = G*sigma*G.T + Noise</span> + <span class="n">PEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">]</span> <span class="o">=</span> <span class="n">G</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">PEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span><span class="n">S</span><span class="p">]</span> <span class="o">@</span> <span class="n">G</span> <span class="o">+</span> <span class="n">Fx</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">Cx</span> <span class="o">@</span> <span class="n">Fx</span> + <span class="k">return</span> <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">G</span><span class="p">,</span> <span class="n">Fx</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">motion_model</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">u</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Computes the motion model based on current state and input function.</span> + +<span class="sd"> :param x: 3x1 pose estimation</span> +<span class="sd"> :param u: 2x1 control input [v; w]</span> +<span class="sd"> :returns: the resulting state after the control function is applied</span> +<span class="sd"> """</span> + <span class="n">F</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]])</span> + + <span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">DT</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="n">DT</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span> <span class="mi">0</span><span class="p">],</span> + <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">DT</span><span class="p">]])</span> + + <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="n">F</span> <span class="o">@</span> <span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">B</span> <span class="o">@</span> <span class="n">u</span><span class="p">)</span> + <span class="k">return</span> <span class="n">x</span> +</pre></div> +</div> +</section> +<section id="update"> +<h2>2 - Update<a class="headerlink" href="#update" title="Permalink to this headline"></a></h2> +<p>In the update phase, the observations of nearby landmarks are used to +correct the location estimate.</p> +<p>For every landmark observed, it is associated to a particular landmark +in the known map. If no landmark exists in the position surrounding the +landmark, it is taken as a NEW landmark. The distance threshold for how +far a landmark must be from the next known landmark before its +considered to be a new landmark is set by <code class="docutils literal notranslate"><span class="pre">M_DIST_TH</span></code>.</p> +<p>With an observation associated to the appropriate landmark, the +<strong>innovation</strong> can be calculated. Innovation (<span class="math notranslate nohighlight">\(y\)</span>) is the +difference between the observation and the observation that <em>should</em> +have been made if the observation were made from the pose predicted in +the predict stage.</p> +<p><span class="math notranslate nohighlight">\(y = z_t - h(X)\)</span></p> +<p>With the innovation calculated, the question becomes which to trust more +- the observations or the predictions? To determine this, we calculate +the Kalman Gain - a percent of how much of the innovation to add to the +prediction based on the uncertainty in the predict step and the update +step.</p> +<p><span class="math notranslate nohighlight">\(K = \bar{P_t}H_t^T(H_t\bar{P_t}H_t^T + Q_t)^{-1}\)</span> +In these equations, <span class="math notranslate nohighlight">\(H\)</span> is the jacobian of the +measurement function. The multiplications by <span class="math notranslate nohighlight">\(H^T\)</span> and <span class="math notranslate nohighlight">\(H\)</span> +represent the application of the delta to the measurement covariance. +Intuitively, this equation is applying the following from the single +variate Kalman equation but in the multivariate form, i.e. finding the +ratio of the uncertainty of the process compared the measurement.</p> +<p>K = <span class="math notranslate nohighlight">\(\frac{\bar{P_t}}{\bar{P_t} + Q_t}\)</span></p> +<p>If <span class="math notranslate nohighlight">\(Q_t << \bar{P_t}\)</span>, (i.e. the measurement covariance is low +relative to the current estimate), then the Kalman gain will be +<span class="math notranslate nohighlight">\(~1\)</span>. This results in adding all of the innovation to the estimate +– and therefore completely believing the measurement.</p> +<p>However, if <span class="math notranslate nohighlight">\(Q_t >> \bar{P_t}\)</span> then the Kalman gain will go to 0, +signaling a high trust in the process and little trust in the +measurement.</p> +<p>The update is captured in the following.</p> +<p><span class="math notranslate nohighlight">\(xUpdate = xEst + (K * y)\)</span></p> +<p>Of course, the covariance must also be updated as well to account for +the changing uncertainty.</p> +<p><span class="math notranslate nohighlight">\(P_{t} = (I-K_tH_t)\bar{P_t}\)</span></p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">initP</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Performs the update step of EKF SLAM</span> + +<span class="sd"> :param xEst: nx1 the predicted pose of the system and the pose of the landmarks</span> +<span class="sd"> :param PEst: nxn the predicted covariance</span> +<span class="sd"> :param u: 2x1 the control function</span> +<span class="sd"> :param z: the measurements read at new position</span> +<span class="sd"> :param initP: 2x2 an identity matrix acting as the initial covariance</span> +<span class="sd"> :returns: the updated state and covariance for the system</span> +<span class="sd"> """</span> + <span class="k">for</span> <span class="n">iz</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">z</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])):</span> <span class="c1"># for each observation</span> + <span class="n">minid</span> <span class="o">=</span> <span class="n">search_correspond_LM_ID</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">z</span><span class="p">[</span><span class="n">iz</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">])</span> <span class="c1"># associate to a known landmark</span> + + <span class="n">nLM</span> <span class="o">=</span> <span class="n">calc_n_LM</span><span class="p">(</span><span class="n">xEst</span><span class="p">)</span> <span class="c1"># number of landmarks we currently know about</span> + + <span class="k">if</span> <span class="n">minid</span> <span class="o">==</span> <span class="n">nLM</span><span class="p">:</span> <span class="c1"># Landmark is a NEW landmark</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"New LM"</span><span class="p">)</span> + <span class="c1"># Extend state and covariance matrix</span> + <span class="n">xAug</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">xEst</span><span class="p">,</span> <span class="n">calc_LM_Pos</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">z</span><span class="p">[</span><span class="n">iz</span><span class="p">,</span> <span class="p">:])))</span> + <span class="n">PAug</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">PEst</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">xEst</span><span class="p">),</span> <span class="n">LM_SIZE</span><span class="p">)))),</span> + <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">LM_SIZE</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">xEst</span><span class="p">))),</span> <span class="n">initP</span><span class="p">))))</span> + <span class="n">xEst</span> <span class="o">=</span> <span class="n">xAug</span> + <span class="n">PEst</span> <span class="o">=</span> <span class="n">PAug</span> + + <span class="n">lm</span> <span class="o">=</span> <span class="n">get_LM_Pos_from_state</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">minid</span><span class="p">)</span> + <span class="n">y</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">H</span> <span class="o">=</span> <span class="n">calc_innovation</span><span class="p">(</span><span class="n">lm</span><span class="p">,</span> <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">z</span><span class="p">[</span><span class="n">iz</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">],</span> <span class="n">minid</span><span class="p">)</span> + + <span class="n">K</span> <span class="o">=</span> <span class="p">(</span><span class="n">PEst</span> <span class="o">@</span> <span class="n">H</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> <span class="o">@</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">S</span><span class="p">)</span> <span class="c1"># Calculate Kalman Gain</span> + <span class="n">xEst</span> <span class="o">=</span> <span class="n">xEst</span> <span class="o">+</span> <span class="p">(</span><span class="n">K</span> <span class="o">@</span> <span class="n">y</span><span class="p">)</span> + <span class="n">PEst</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">xEst</span><span class="p">))</span> <span class="o">-</span> <span class="p">(</span><span class="n">K</span> <span class="o">@</span> <span class="n">H</span><span class="p">))</span> <span class="o">@</span> <span class="n">PEst</span> + + <span class="n">xEst</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">xEst</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> + <span class="k">return</span> <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">calc_innovation</span><span class="p">(</span><span class="n">lm</span><span class="p">,</span> <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">LMid</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calculates the innovation based on expected position and landmark position</span> + +<span class="sd"> :param lm: landmark position</span> +<span class="sd"> :param xEst: estimated position/state</span> +<span class="sd"> :param PEst: estimated covariance</span> +<span class="sd"> :param z: read measurements</span> +<span class="sd"> :param LMid: landmark id</span> +<span class="sd"> :returns: returns the innovation y, and the jacobian H, and S, used to calculate the Kalman Gain</span> +<span class="sd"> """</span> + <span class="n">delta</span> <span class="o">=</span> <span class="n">lm</span> <span class="o">-</span> <span class="n">xEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span> + <span class="n">q</span> <span class="o">=</span> <span class="p">(</span><span class="n">delta</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">delta</span><span class="p">)[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">zangle</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">atan2</span><span class="p">(</span><span class="n">delta</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">delta</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="o">-</span> <span class="n">xEst</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">zp</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">q</span><span class="p">),</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">zangle</span><span class="p">)]])</span> + <span class="c1"># zp is the expected measurement based on xEst and the expected landmark position</span> + + <span class="n">y</span> <span class="o">=</span> <span class="p">(</span><span class="n">z</span> <span class="o">-</span> <span class="n">zp</span><span class="p">)</span><span class="o">.</span><span class="n">T</span> <span class="c1"># y = innovation</span> + <span class="n">y</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + + <span class="n">H</span> <span class="o">=</span> <span class="n">jacobH</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">delta</span><span class="p">,</span> <span class="n">xEst</span><span class="p">,</span> <span class="n">LMid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> + <span class="n">S</span> <span class="o">=</span> <span class="n">H</span> <span class="o">@</span> <span class="n">PEst</span> <span class="o">@</span> <span class="n">H</span><span class="o">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">Cx</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span> + + <span class="k">return</span> <span class="n">y</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">H</span> + +<span class="k">def</span> <span class="nf">jacobH</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">delta</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">i</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calculates the jacobian of the measurement function</span> + +<span class="sd"> :param q: the range from the system pose to the landmark</span> +<span class="sd"> :param delta: the difference between a landmark position and the estimated system position</span> +<span class="sd"> :param x: the state, including the estimated system position</span> +<span class="sd"> :param i: landmark id + 1</span> +<span class="sd"> :returns: the jacobian H</span> +<span class="sd"> """</span> + <span class="n">sq</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">q</span><span class="p">)</span> + <span class="n">G</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="o">-</span><span class="n">sq</span> <span class="o">*</span> <span class="n">delta</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="o">-</span> <span class="n">sq</span> <span class="o">*</span> <span class="n">delta</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sq</span> <span class="o">*</span> <span class="n">delta</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">sq</span> <span class="o">*</span> <span class="n">delta</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]],</span> + <span class="p">[</span><span class="n">delta</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="o">-</span> <span class="n">delta</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="o">-</span> <span class="n">q</span><span class="p">,</span> <span class="o">-</span> <span class="n">delta</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">delta</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]]])</span> + + <span class="n">G</span> <span class="o">=</span> <span class="n">G</span> <span class="o">/</span> <span class="n">q</span> + <span class="n">nLM</span> <span class="o">=</span> <span class="n">calc_n_LM</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> + <span class="n">F1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">nLM</span><span class="p">))))</span> + <span class="n">F2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)),</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))),</span> + <span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">nLM</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">i</span><span class="p">))))</span> + + <span class="n">F</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">F1</span><span class="p">,</span> <span class="n">F2</span><span class="p">))</span> + + <span class="n">H</span> <span class="o">=</span> <span class="n">G</span> <span class="o">@</span> <span class="n">F</span> + + <span class="k">return</span> <span class="n">H</span> +</pre></div> +</div> +</section> +<section id="observation-step"> +<h2>Observation Step<a class="headerlink" href="#observation-step" title="Permalink to this headline"></a></h2> +<p>The observation step described here is outside the main EKF SLAM process +and is primarily used as a method of driving the simulation. The +observations function is in charge of calculating how the poses of the +robots change and accumulate error over time, and the theoretical +measurements that are expected as a result of each measurement.</p> +<p>Observations are based on the TRUE position of the robot. Error in dead +reckoning and control functions are passed along here as well.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">observation</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">xd</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">RFID</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> :param xTrue: the true pose of the system</span> +<span class="sd"> :param xd: the current noisy estimate of the system</span> +<span class="sd"> :param u: the current control input</span> +<span class="sd"> :param RFID: the true position of the landmarks</span> + +<span class="sd"> :returns: Computes the true position, observations, dead reckoning (noisy) position,</span> +<span class="sd"> and noisy control function</span> +<span class="sd"> """</span> + <span class="n">xTrue</span> <span class="o">=</span> <span class="n">motion_model</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">u</span><span class="p">)</span> + + <span class="c1"># add noise to gps x-y</span> + <span class="n">z</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span> + + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">RFID</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])):</span> <span class="c1"># Test all beacons, only add the ones we can see (within MAX_RANGE)</span> + + <span class="n">dx</span> <span class="o">=</span> <span class="n">RFID</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">xTrue</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">dy</span> <span class="o">=</span> <span class="n">RFID</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">xTrue</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">dx</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">dy</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> + <span class="n">angle</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">atan2</span><span class="p">(</span><span class="n">dy</span><span class="p">,</span> <span class="n">dx</span><span class="p">)</span> <span class="o">-</span> <span class="n">xTrue</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> + <span class="k">if</span> <span class="n">d</span> <span class="o"><=</span> <span class="n">MAX_RANGE</span><span class="p">:</span> + <span class="n">dn</span> <span class="o">=</span> <span class="n">d</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Qsim</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="c1"># add noise</span> + <span class="n">anglen</span> <span class="o">=</span> <span class="n">angle</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Qsim</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="c1"># add noise</span> + <span class="n">zi</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">dn</span><span class="p">,</span> <span class="n">anglen</span><span class="p">,</span> <span class="n">i</span><span class="p">])</span> + <span class="n">z</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">z</span><span class="p">,</span> <span class="n">zi</span><span class="p">))</span> + + <span class="c1"># add noise to input</span> + <span class="n">ud</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span> + <span class="n">u</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Rsim</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> + <span class="n">u</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">()</span> <span class="o">*</span> <span class="n">Rsim</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]]])</span><span class="o">.</span><span class="n">T</span> + + <span class="n">xd</span> <span class="o">=</span> <span class="n">motion_model</span><span class="p">(</span><span class="n">xd</span><span class="p">,</span> <span class="n">ud</span><span class="p">)</span> + <span class="k">return</span> <span class="n">xTrue</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">xd</span><span class="p">,</span> <span class="n">ud</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">calc_n_LM</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calculates the number of landmarks currently tracked in the state</span> +<span class="sd"> :param x: the state</span> +<span class="sd"> :returns: the number of landmarks n</span> +<span class="sd"> """</span> + <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">STATE_SIZE</span><span class="p">)</span> <span class="o">/</span> <span class="n">LM_SIZE</span><span class="p">)</span> + <span class="k">return</span> <span class="n">n</span> + + +<span class="k">def</span> <span class="nf">jacob_motion</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">u</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calculates the jacobian of motion model.</span> + +<span class="sd"> :param x: The state, including the estimated position of the system</span> +<span class="sd"> :param u: The control function</span> +<span class="sd"> :returns: G: Jacobian</span> +<span class="sd"> Fx: STATE_SIZE x (STATE_SIZE + 2 * num_landmarks) matrix where the left side is an identity matrix</span> +<span class="sd"> """</span> + + <span class="c1"># [eye(3) [0 x y; 0 x y; 0 x y]]</span> + <span class="n">Fx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="n">STATE_SIZE</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span> + <span class="p">(</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="n">LM_SIZE</span> <span class="o">*</span> <span class="n">calc_n_LM</span><span class="p">(</span><span class="n">x</span><span class="p">)))))</span> + + <span class="n">jF</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="o">-</span><span class="n">DT</span> <span class="o">*</span> <span class="n">u</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])],</span> + <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="n">DT</span> <span class="o">*</span> <span class="n">u</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])],</span> + <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]],</span><span class="n">dtype</span><span class="o">=</span><span class="nb">object</span><span class="p">)</span> + + <span class="n">G</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="n">STATE_SIZE</span><span class="p">)</span> <span class="o">+</span> <span class="n">Fx</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">jF</span> <span class="o">@</span> <span class="n">Fx</span> + <span class="k">if</span> <span class="n">calc_n_LM</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> + <span class="nb">print</span><span class="p">(</span><span class="n">Fx</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span> + <span class="k">return</span> <span class="n">G</span><span class="p">,</span> <span class="n">Fx</span><span class="p">,</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">calc_LM_Pos</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">z</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Calculates the pose in the world coordinate frame of a landmark at the given measurement.</span> + +<span class="sd"> :param x: [x; y; theta]</span> +<span class="sd"> :param z: [range; bearing]</span> +<span class="sd"> :returns: [x; y] for given measurement</span> +<span class="sd"> """</span> + <span class="n">zp</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> + + <span class="n">zp</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">z</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="n">zp</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">z</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">z</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="c1">#zp[0, 0] = x[0, 0] + z[0, 0] * math.cos(x[2, 0] + z[0, 1])</span> + <span class="c1">#zp[1, 0] = x[1, 0] + z[0, 0] * math.sin(x[2, 0] + z[0, 1])</span> + + <span class="k">return</span> <span class="n">zp</span> + + +<span class="k">def</span> <span class="nf">get_LM_Pos_from_state</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">ind</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Returns the position of a given landmark</span> + +<span class="sd"> :param x: The state containing all landmark positions</span> +<span class="sd"> :param ind: landmark id</span> +<span class="sd"> :returns: The position of the landmark</span> +<span class="sd"> """</span> + <span class="n">lm</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="n">STATE_SIZE</span> <span class="o">+</span> <span class="n">LM_SIZE</span> <span class="o">*</span> <span class="n">ind</span><span class="p">:</span> <span class="n">STATE_SIZE</span> <span class="o">+</span> <span class="n">LM_SIZE</span> <span class="o">*</span> <span class="p">(</span><span class="n">ind</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="p">:]</span> + + <span class="k">return</span> <span class="n">lm</span> + + +<span class="k">def</span> <span class="nf">search_correspond_LM_ID</span><span class="p">(</span><span class="n">xAug</span><span class="p">,</span> <span class="n">PAug</span><span class="p">,</span> <span class="n">zi</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Landmark association with Mahalanobis distance.</span> + +<span class="sd"> If this landmark is at least M_DIST_TH units away from all known landmarks,</span> +<span class="sd"> it is a NEW landmark.</span> + +<span class="sd"> :param xAug: The estimated state</span> +<span class="sd"> :param PAug: The estimated covariance</span> +<span class="sd"> :param zi: the read measurements of specific landmark</span> +<span class="sd"> :returns: landmark id</span> +<span class="sd"> """</span> + + <span class="n">nLM</span> <span class="o">=</span> <span class="n">calc_n_LM</span><span class="p">(</span><span class="n">xAug</span><span class="p">)</span> + + <span class="n">mdist</span> <span class="o">=</span> <span class="p">[]</span> + + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">nLM</span><span class="p">):</span> + <span class="n">lm</span> <span class="o">=</span> <span class="n">get_LM_Pos_from_state</span><span class="p">(</span><span class="n">xAug</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> + <span class="n">y</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">H</span> <span class="o">=</span> <span class="n">calc_innovation</span><span class="p">(</span><span class="n">lm</span><span class="p">,</span> <span class="n">xAug</span><span class="p">,</span> <span class="n">PAug</span><span class="p">,</span> <span class="n">zi</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> + <span class="n">mdist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">S</span><span class="p">)</span> <span class="o">@</span> <span class="n">y</span><span class="p">)</span> + + <span class="n">mdist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">M_DIST_TH</span><span class="p">)</span> <span class="c1"># new landmark</span> + + <span class="n">minid</span> <span class="o">=</span> <span class="n">mdist</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="n">mdist</span><span class="p">))</span> + + <span class="k">return</span> <span class="n">minid</span> + +<span class="k">def</span> <span class="nf">calc_input</span><span class="p">():</span> + <span class="n">v</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1"># [m/s]</span> + <span class="n">yawrate</span> <span class="o">=</span> <span class="mf">0.1</span> <span class="c1"># [rad/s]</span> + <span class="n">u</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="n">v</span><span class="p">,</span> <span class="n">yawrate</span><span class="p">]])</span><span class="o">.</span><span class="n">T</span> + <span class="k">return</span> <span class="n">u</span> + +<span class="k">def</span> <span class="nf">pi_2_pi</span><span class="p">(</span><span class="n">angle</span><span class="p">):</span> + <span class="k">return</span> <span class="p">(</span><span class="n">angle</span> <span class="o">+</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">-</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">main</span><span class="p">():</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">" start!!"</span><span class="p">)</span> + + <span class="n">time</span> <span class="o">=</span> <span class="mf">0.0</span> + + <span class="c1"># RFID positions [x, y]</span> + <span class="n">RFID</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">10.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">],</span> + <span class="p">[</span><span class="mf">15.0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">],</span> + <span class="p">[</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">15.0</span><span class="p">],</span> + <span class="p">[</span><span class="o">-</span><span class="mf">5.0</span><span class="p">,</span> <span class="mf">20.0</span><span class="p">]])</span> + + <span class="c1"># State Vector [x y yaw v]'</span> + <span class="n">xEst</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> + <span class="n">xTrue</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> + <span class="n">PEst</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="n">STATE_SIZE</span><span class="p">)</span> + + <span class="n">xDR</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="c1"># Dead reckoning</span> + + <span class="c1"># history</span> + <span class="n">hxEst</span> <span class="o">=</span> <span class="n">xEst</span> + <span class="n">hxTrue</span> <span class="o">=</span> <span class="n">xTrue</span> + <span class="n">hxDR</span> <span class="o">=</span> <span class="n">xTrue</span> + + <span class="k">while</span> <span class="n">SIM_TIME</span> <span class="o">>=</span> <span class="n">time</span><span class="p">:</span> + <span class="n">time</span> <span class="o">+=</span> <span class="n">DT</span> + <span class="n">u</span> <span class="o">=</span> <span class="n">calc_input</span><span class="p">()</span> + + <span class="n">xTrue</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">xDR</span><span class="p">,</span> <span class="n">ud</span> <span class="o">=</span> <span class="n">observation</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">xDR</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">RFID</span><span class="p">)</span> + + <span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span> <span class="o">=</span> <span class="n">ekf_slam</span><span class="p">(</span><span class="n">xEst</span><span class="p">,</span> <span class="n">PEst</span><span class="p">,</span> <span class="n">ud</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span> + + <span class="n">x_state</span> <span class="o">=</span> <span class="n">xEst</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">STATE_SIZE</span><span class="p">]</span> + + <span class="c1"># store data history</span> + <span class="n">hxEst</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">hxEst</span><span class="p">,</span> <span class="n">x_state</span><span class="p">))</span> + <span class="n">hxDR</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">hxDR</span><span class="p">,</span> <span class="n">xDR</span><span class="p">))</span> + <span class="n">hxTrue</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">hxTrue</span><span class="p">,</span> <span class="n">xTrue</span><span class="p">))</span> + + <span class="k">if</span> <span class="n">show_animation</span><span class="p">:</span> <span class="c1"># pragma: no cover</span> + <span class="n">plt</span><span class="o">.</span><span class="n">cla</span><span class="p">()</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">RFID</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">RFID</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span> <span class="s2">"*k"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xEst</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">xEst</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">".r"</span><span class="p">)</span> + + <span class="c1"># plot landmark</span> + <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">calc_n_LM</span><span class="p">(</span><span class="n">xEst</span><span class="p">)):</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xEst</span><span class="p">[</span><span class="n">STATE_SIZE</span> <span class="o">+</span> <span class="n">i</span> <span class="o">*</span> <span class="mi">2</span><span class="p">],</span> + <span class="n">xEst</span><span class="p">[</span><span class="n">STATE_SIZE</span> <span class="o">+</span> <span class="n">i</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="s2">"xg"</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">hxTrue</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:],</span> + <span class="n">hxTrue</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="s2">"-b"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">hxDR</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:],</span> + <span class="n">hxDR</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="s2">"-k"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">hxEst</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:],</span> + <span class="n">hxEst</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="s2">"-r"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">"equal"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">pause</span><span class="p">(</span><span class="mf">0.001</span><span class="p">)</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="o">%</span><span class="k">matplotlib</span> notebook +<span class="n">main</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> start!! +New LM +New LM +New LM +</pre></div> +</div> +<img alt="../../../_images/ekf_slam_1_0.png" src="../../../_images/ekf_slam_1_0.png" /> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www.probabilistic-robotics.org/">PROBABILISTIC ROBOTICS</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../iterative_closest_point_matching/iterative_closest_point_matching.html" class="btn btn-neutral float-left" title="Iterative Closest Point (ICP) Matching" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../FastSLAM1/FastSLAM1.html" class="btn btn-neutral float-right" title="FastSLAM1.0" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/slam/graph_slam/graph_slam.html b/modules/slam/graph_slam/graph_slam.html new file mode 100644 index 00000000000..5ce2f4dd680 --- /dev/null +++ b/modules/slam/graph_slam/graph_slam.html @@ -0,0 +1,1025 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Graph based SLAM — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Path Planning" href="../../path_planning/path_planning.html" /> + <link rel="prev" title="FastSLAM 2.0" href="../FastSLAM2/FastSLAM2.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../slam.html">SLAM</a><ul class="current"> +<li class="toctree-l2"><a class="reference internal" href="../iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a></li> +<li class="toctree-l2"><a class="reference internal" href="../ekf_slam/ekf_slam.html">EKF SLAM</a></li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM1/FastSLAM1.html">FastSLAM1.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a></li> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Graph based SLAM</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#graph-slam">Graph SLAM</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#introduction">Introduction</a></li> +<li class="toctree-l4"><a class="reference internal" href="#minimal-example">Minimal Example</a></li> +<li class="toctree-l4"><a class="reference internal" href="#graph-optimization">Graph Optimization</a></li> +<li class="toctree-l4"><a class="reference internal" href="#planar-example">Planar Example:</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-references">The references:</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#graph-slam-formulation">Graph SLAM Formulation</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#problem-formulation">Problem Formulation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#dimensionality-and-pose-representation">Dimensionality and Pose Representation</a></li> +<li class="toctree-l4"><a class="reference internal" href="#graph-slam-algorithm">Graph SLAM Algorithm</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#graph-slam-for-a-real-world-se-2-dataset">Graph SLAM for a real-world SE(2) dataset</a><ul> +<li class="toctree-l4"><a class="reference internal" href="#id4">Introduction</a></li> +<li class="toctree-l4"><a class="reference internal" href="#the-dataset">The Dataset</a></li> +<li class="toctree-l4"><a class="reference internal" href="#optimization">Optimization</a></li> +</ul> +</li> +<li class="toctree-l3"><a class="reference internal" href="#references">References:</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../slam.html">SLAM</a> »</li> + <li>Graph based SLAM</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/slam/graph_slam/graph_slam_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="graph-based-slam"> +<h1>Graph based SLAM<a class="headerlink" href="#graph-based-slam" title="Permalink to this headline"></a></h1> +<p>This is a graph based SLAM example.</p> +<p>The blue line is ground truth.</p> +<p>The black line is dead reckoning.</p> +<p>The red line is the estimated trajectory with Graph based SLAM.</p> +<p>The black stars are landmarks for graph edge generation.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/GraphBasedSLAM/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/GraphBasedSLAM/animation.gif" /> +<section id="graph-slam"> +<h2>Graph SLAM<a class="headerlink" href="#graph-slam" title="Permalink to this headline"></a></h2> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">copy</span> +<span class="kn">import</span> <span class="nn">math</span> +<span class="kn">import</span> <span class="nn">itertools</span> +<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> +<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span> +<span class="kn">from</span> <span class="nn">graph_based_slam</span> <span class="kn">import</span> <span class="n">calc_rotational_matrix</span><span class="p">,</span> <span class="n">calc_jacobian</span><span class="p">,</span> <span class="n">cal_observation_sigma</span><span class="p">,</span> \ + <span class="n">calc_input</span><span class="p">,</span> <span class="n">observation</span><span class="p">,</span> <span class="n">motion_model</span><span class="p">,</span> <span class="n">Edge</span><span class="p">,</span> <span class="n">pi_2_pi</span> + +<span class="o">%</span><span class="k">matplotlib</span> inline +<span class="n">np</span><span class="o">.</span><span class="n">set_printoptions</span><span class="p">(</span><span class="n">precision</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">suppress</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> +<span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> +</pre></div> +</div> +<section id="introduction"> +<h3>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h3> +<p>In contrast to the probabilistic approaches for solving SLAM, such as +EKF, UKF, particle filters, and so on, the graph technique formulates +the SLAM as an optimization problem. It is mostly used to solve the full +SLAM problem in an offline fashion, i.e. optimize all the poses of the +robot after the path has been traversed. However, some variants are +available that uses graph-based approaches to perform online estimation +or to solve for a subset of the poses.</p> +<p>GraphSLAM uses the motion information as well as the observations of the +environment to create least square problem that can be solved using +standard optimization techniques.</p> +</section> +<section id="minimal-example"> +<h3>Minimal Example<a class="headerlink" href="#minimal-example" title="Permalink to this headline"></a></h3> +<p>The following example illustrates the main idea behind graphSLAM. A +simple case of a 1D robot is considered that can only move in 1 +direction. The robot is commanded to move forward with a control input +<span class="math notranslate nohighlight">\(u_t=1\)</span>, however, the motion is not perfect and the measured +odometry will deviate from the true path. At each time step the robot can +observe its environment, for this simple case as well, there is only a +single landmark at coordinates <span class="math notranslate nohighlight">\(x=3\)</span>. The measured observations +are the range between the robot and landmark. These measurements are +also subjected to noise. No bearing information is required since this +is a 1D problem.</p> +<p>To solve this, graphSLAM creates what is called as the system +information matrix <span class="math notranslate nohighlight">\(\Omega\)</span> also referred to as <span class="math notranslate nohighlight">\(H\)</span> and the +information vector <span class="math notranslate nohighlight">\(\xi\)</span> also known as <span class="math notranslate nohighlight">\(b\)</span>. The entries are +created based on the information of the motion and the observation.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">R</span> <span class="o">=</span> <span class="mf">0.2</span> +<span class="n">Q</span> <span class="o">=</span> <span class="mf">0.2</span> +<span class="n">N</span> <span class="o">=</span> <span class="mi">3</span> +<span class="n">graphics_radius</span> <span class="o">=</span> <span class="mf">0.1</span> + +<span class="n">odom</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="n">N</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span> +<span class="n">obs</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="n">N</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span> +<span class="n">x_true</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="n">N</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span> + +<span class="n">landmark</span> <span class="o">=</span> <span class="mi">3</span> +<span class="c1"># Simulated readings of odometry and observations</span> +<span class="n">x_true</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">odom</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">obs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">2.9</span> +<span class="n">x_true</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">odom</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">obs</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">,</span> <span class="mf">2.0</span> +<span class="n">x_true</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">odom</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">obs</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.4</span><span class="p">,</span> <span class="mf">1.0</span> + +<span class="n">hxDR</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">odom</span><span class="p">)</span> +<span class="c1"># Visualization</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">landmark</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span> <span class="s1">'*k'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">odom</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'steelblue'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">odom</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">odom</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">graphics_radius</span><span class="p">],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span> <span class="s1">'r'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="n">odom</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mf">0.02</span><span class="p">,</span> <span class="s2">"X_</span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">12</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">obs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="n">odom</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="mi">0</span><span class="p">,</span><span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">25</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'brown'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x_true</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="mi">0</span><span class="p">,</span><span class="s1">'.g'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + + +<span class="c1"># Defined as a function to facilitate iteration</span> +<span class="k">def</span> <span class="nf">get_H_b</span><span class="p">(</span><span class="n">odom</span><span class="p">,</span> <span class="n">obs</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""</span> +<span class="sd"> Create the information matrix and information vector. This implementation is</span> +<span class="sd"> based on the concept of virtual measurement i.e. the observations of the</span> +<span class="sd"> landmarks are converted into constraints (edges) between the nodes that</span> +<span class="sd"> have observed this landmark.</span> +<span class="sd"> """</span> + <span class="n">measure_constraints</span> <span class="o">=</span> <span class="p">{}</span> + <span class="n">omegas</span> <span class="o">=</span> <span class="p">{}</span> + <span class="n">zids</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">combinations</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">N</span><span class="p">),</span><span class="mi">2</span><span class="p">))</span> + <span class="n">H</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">N</span><span class="p">,</span><span class="n">N</span><span class="p">))</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">N</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span> + <span class="k">for</span> <span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">)</span> <span class="ow">in</span> <span class="n">zids</span><span class="p">:</span> + <span class="n">x1</span> <span class="o">=</span> <span class="n">odom</span><span class="p">[</span><span class="n">t1</span><span class="p">]</span> + <span class="n">x2</span> <span class="o">=</span> <span class="n">odom</span><span class="p">[</span><span class="n">t2</span><span class="p">]</span> + <span class="n">z1</span> <span class="o">=</span> <span class="n">obs</span><span class="p">[</span><span class="n">t1</span><span class="p">]</span> + <span class="n">z2</span> <span class="o">=</span> <span class="n">obs</span><span class="p">[</span><span class="n">t2</span><span class="p">]</span> + + <span class="c1"># Adding virtual measurement constraint</span> + <span class="n">measure_constraints</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> <span class="o">=</span> <span class="p">(</span><span class="n">x2</span><span class="o">-</span><span class="n">x1</span><span class="o">-</span><span class="n">z1</span><span class="o">+</span><span class="n">z2</span><span class="p">)</span> + <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">Q</span><span class="p">))</span> + + <span class="c1"># populate system's information matrix and vector</span> + <span class="n">H</span><span class="p">[</span><span class="n">t1</span><span class="p">,</span><span class="n">t1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> + <span class="n">H</span><span class="p">[</span><span class="n">t2</span><span class="p">,</span><span class="n">t2</span><span class="p">]</span> <span class="o">+=</span> <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> + <span class="n">H</span><span class="p">[</span><span class="n">t2</span><span class="p">,</span><span class="n">t1</span><span class="p">]</span> <span class="o">-=</span> <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> + <span class="n">H</span><span class="p">[</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">]</span> <span class="o">-=</span> <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> + + <span class="n">b</span><span class="p">[</span><span class="n">t1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> <span class="o">*</span> <span class="n">measure_constraints</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> + <span class="n">b</span><span class="p">[</span><span class="n">t2</span><span class="p">]</span> <span class="o">-=</span> <span class="n">omegas</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> <span class="o">*</span> <span class="n">measure_constraints</span><span class="p">[(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">)]</span> + + <span class="k">return</span> <span class="n">H</span><span class="p">,</span> <span class="n">b</span> + + +<span class="n">H</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">get_H_b</span><span class="p">(</span><span class="n">odom</span><span class="p">,</span> <span class="n">obs</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"The determinant of H: "</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">det</span><span class="p">(</span><span class="n">H</span><span class="p">))</span> +<span class="n">H</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># np.inf ?</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"The determinant of H after anchoring constraint: "</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">det</span><span class="p">(</span><span class="n">H</span><span class="p">))</span> + +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span> + <span class="n">H</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">get_H_b</span><span class="p">(</span><span class="n">odom</span><span class="p">,</span> <span class="n">obs</span><span class="p">)</span> + <span class="n">H</span><span class="p">[(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="o">+=</span> <span class="mi">1</span> + + <span class="c1"># Recover the posterior over the path</span> + <span class="n">dx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">H</span><span class="p">)</span> <span class="o">@</span> <span class="n">b</span> + <span class="n">odom</span> <span class="o">+=</span> <span class="n">dx</span> + <span class="c1"># repeat till convergence</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Running graphSLAM ..."</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Odometry values after optimzation: </span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">odom</span><span class="p">)</span> + +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x_true</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">x_true</span><span class="o">.</span><span class="n">shape</span><span class="p">),</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'Ground truth'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">odom</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">x_true</span><span class="o">.</span><span class="n">shape</span><span class="p">),</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'Estimation'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">hxDR</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">x_true</span><span class="o">.</span><span class="n">shape</span><span class="p">),</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'Odom'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_doc_2_0.png" src="../../../_images/graphSLAM_doc_2_0.png" /> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">The</span> <span class="n">determinant</span> <span class="n">of</span> <span class="n">H</span><span class="p">:</span> <span class="mf">0.0</span> +<span class="n">The</span> <span class="n">determinant</span> <span class="n">of</span> <span class="n">H</span> <span class="n">after</span> <span class="n">anchoring</span> <span class="n">constraint</span><span class="p">:</span> <span class="mf">18.750000000000007</span> +<span class="n">Running</span> <span class="n">graphSLAM</span> <span class="o">...</span> +<span class="n">Odometry</span> <span class="n">values</span> <span class="n">after</span> <span class="n">optimzation</span><span class="p">:</span> + <span class="p">[[</span><span class="o">-</span><span class="mf">0.</span> <span class="p">]</span> + <span class="p">[</span> <span class="mf">0.9</span><span class="p">]</span> + <span class="p">[</span> <span class="mf">1.9</span><span class="p">]]</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_doc_2_2.png" src="../../../_images/graphSLAM_doc_2_2.png" /> +<p>In particular, the tasks are split into 2 parts, graph construction, and +graph optimization. ### Graph Construction</p> +<p>Firstly the nodes are defined +<span class="math notranslate nohighlight">\(\boldsymbol{x} = \boldsymbol{x}_{1:n}\)</span> such that each node is the +pose of the robot at time <span class="math notranslate nohighlight">\(t_i\)</span> Secondly, the edges i.e. the +constraints, are constructed according to the following conditions:</p> +<ul class="simple"> +<li><p>robot moves from <span class="math notranslate nohighlight">\(\boldsymbol{x}_i\)</span> to +<span class="math notranslate nohighlight">\(\boldsymbol{x}_j\)</span>. This edge corresponds to the odometry +measurement. Relative motion constraints (Not included in the +previous minimal example).</p></li> +<li><p>Measurement constraints, this can be done in two ways:</p> +<ul> +<li><p>The information matrix is set in such a way that it includes the +landmarks in the map as well. Then the constraints can be entered +in a straightforward fashion between a node +<span class="math notranslate nohighlight">\(\boldsymbol{x}_i\)</span> and some landmark <span class="math notranslate nohighlight">\(m_k\)</span></p></li> +<li><p>Through creating a virtual measurement among all the node that +have observed the same landmark. More concretely, robot observes +the same landmark from <span class="math notranslate nohighlight">\(\boldsymbol{x}_i\)</span> and +<span class="math notranslate nohighlight">\(\boldsymbol{x}_j\)</span>. Relative measurement constraint. The +“virtual measurement” <span class="math notranslate nohighlight">\(\boldsymbol{z}_{ij}\)</span>, which is the +estimated pose of <span class="math notranslate nohighlight">\(\boldsymbol{x}_j\)</span> as seen from the node +<span class="math notranslate nohighlight">\(\boldsymbol{x}_i\)</span>. The virtual measurement can then be +entered in the information matrix and vector in a similar fashion +to the motion constraints.</p></li> +</ul> +</li> +</ul> +<p>An edge is fully characterized by the values of the error (entry to +information vector) and the local information matrix (entry to the +system’s information vector). The larger the local information matrix +(lower <span class="math notranslate nohighlight">\(Q\)</span> or <span class="math notranslate nohighlight">\(R\)</span>) the values that this edge will contribute +with.</p> +<p>Important Notes:</p> +<ul class="simple"> +<li><p>The addition to the information matrix and vector are added to the +earlier values.</p></li> +<li><p>In the case of 2D robot, the constraints will be non-linear, +therefore, a Jacobian of the error w.r.t the states is needed when +updated <span class="math notranslate nohighlight">\(H\)</span> and <span class="math notranslate nohighlight">\(b\)</span>.</p></li> +<li><p>The anchoring constraint is needed in order to avoid having a +singular information matri.</p></li> +</ul> +</section> +<section id="graph-optimization"> +<h3>Graph Optimization<a class="headerlink" href="#graph-optimization" title="Permalink to this headline"></a></h3> +<p>The result from this formulation yields an overdetermined system of +equations. The goal after constructing the graph is to find: +<span class="math notranslate nohighlight">\(x^*=\underset{x}{\mathrm{argmin}}~\underset{ij}\Sigma~f(e_{ij})\)</span>, +where <span class="math notranslate nohighlight">\(f\)</span> is some error function that depends on the edges between +to related nodes <span class="math notranslate nohighlight">\(i\)</span> and <span class="math notranslate nohighlight">\(j\)</span>. The derivation in the references +arrive at the solution for <span class="math notranslate nohighlight">\(x^* = H^{-1}b\)</span></p> +</section> +<section id="planar-example"> +<h3>Planar Example:<a class="headerlink" href="#planar-example" title="Permalink to this headline"></a></h3> +<p>Now we will go through an example with a more realistic case of a 2D +robot with 3DoF, namely, <span class="math notranslate nohighlight">\([x, y, \theta]^T\)</span></p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Simulation parameter</span> +<span class="n">Qsim</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">0.01</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">0.010</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> <span class="c1"># error added to range and bearing</span> +<span class="n">Rsim</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)])</span><span class="o">**</span><span class="mi">2</span> <span class="c1"># error added to [v, w]</span> + +<span class="n">DT</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="c1"># time tick [s]</span> +<span class="n">SIM_TIME</span> <span class="o">=</span> <span class="mf">100.0</span> <span class="c1"># simulation time [s]</span> +<span class="n">MAX_RANGE</span> <span class="o">=</span> <span class="mf">30.0</span> <span class="c1"># maximum observation range</span> +<span class="n">STATE_SIZE</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1"># State size [x,y,yaw]</span> + +<span class="c1"># TODO: Why not use Qsim ?</span> +<span class="c1"># Covariance parameter of Graph Based SLAM</span> +<span class="n">C_SIGMA1</span> <span class="o">=</span> <span class="mf">0.1</span> +<span class="n">C_SIGMA2</span> <span class="o">=</span> <span class="mf">0.1</span> +<span class="n">C_SIGMA3</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)</span> + +<span class="n">MAX_ITR</span> <span class="o">=</span> <span class="mi">20</span> <span class="c1"># Maximum iteration during optimization</span> +<span class="n">timesteps</span> <span class="o">=</span> <span class="mi">1</span> + +<span class="c1"># consider only 2 landmarks for simplicity</span> +<span class="c1"># RFID positions [x, y, yaw]</span> +<span class="n">RFID</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">10.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">],</span> +<span class="c1"># [15.0, 10.0, 0.0],</span> +<span class="c1"># [3.0, 15.0, 0.0],</span> +<span class="c1"># [-5.0, 20.0, 0.0],</span> +<span class="c1"># [-5.0, 5.0, 0.0]</span> + <span class="p">])</span> + +<span class="c1"># State Vector [x y yaw v]'</span> +<span class="n">xTrue</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> +<span class="n">xDR</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="c1"># Dead reckoning</span> +<span class="n">xTrue</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mi">45</span><span class="p">)</span> +<span class="n">xDR</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">deg2rad</span><span class="p">(</span><span class="mi">45</span><span class="p">)</span> +<span class="c1"># history initial values</span> +<span class="n">hxTrue</span> <span class="o">=</span> <span class="n">xTrue</span> +<span class="n">hxDR</span> <span class="o">=</span> <span class="n">xTrue</span> +<span class="n">_</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">observation</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">xDR</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]])</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">RFID</span><span class="p">)</span> +<span class="n">hz</span> <span class="o">=</span> <span class="p">[</span><span class="n">z</span><span class="p">]</span> + +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">timesteps</span><span class="p">):</span> + <span class="n">u</span> <span class="o">=</span> <span class="n">calc_input</span><span class="p">()</span> + <span class="n">xTrue</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">xDR</span><span class="p">,</span> <span class="n">ud</span> <span class="o">=</span> <span class="n">observation</span><span class="p">(</span><span class="n">xTrue</span><span class="p">,</span> <span class="n">xDR</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">RFID</span><span class="p">)</span> + <span class="n">hxDR</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">hxDR</span><span class="p">,</span> <span class="n">xDR</span><span class="p">))</span> + <span class="n">hxTrue</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">hstack</span><span class="p">((</span><span class="n">hxTrue</span><span class="p">,</span> <span class="n">xTrue</span><span class="p">))</span> + <span class="n">hz</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> + +<span class="c1"># visualize</span> +<span class="n">graphics_radius</span> <span class="o">=</span> <span class="mf">0.3</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">RFID</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">RFID</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span> <span class="s2">"*k"</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">hxDR</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:],</span> <span class="n">hxDR</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'Odom'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">hxTrue</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:],</span> <span class="n">hxTrue</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'X_true'</span><span class="p">)</span> + +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">hxDR</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span> + <span class="n">x</span> <span class="o">=</span> <span class="n">hxDR</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> + <span class="n">y</span> <span class="o">=</span> <span class="n">hxDR</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> + <span class="n">yaw</span> <span class="o">=</span> <span class="n">hxDR</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span> <span class="o">+</span> <span class="n">graphics_radius</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">yaw</span><span class="p">)],</span> + <span class="p">[</span><span class="n">y</span><span class="p">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">graphics_radius</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">yaw</span><span class="p">)],</span> <span class="s1">'r'</span><span class="p">)</span> + <span class="n">d</span> <span class="o">=</span> <span class="n">hz</span><span class="p">[</span><span class="n">i</span><span class="p">][:,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">angle</span> <span class="o">=</span> <span class="n">hz</span><span class="p">[</span><span class="n">i</span><span class="p">][:,</span> <span class="mi">1</span><span class="p">]</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x</span> <span class="o">+</span> <span class="n">d</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">angle</span> <span class="o">+</span> <span class="n">yaw</span><span class="p">)],</span> <span class="p">[</span><span class="n">y</span> <span class="o">+</span> <span class="n">d</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">angle</span> <span class="o">+</span> <span class="n">yaw</span><span class="p">)],</span> <span class="s1">'.'</span><span class="p">,</span> + <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_doc_4_0.png" src="../../../_images/graphSLAM_doc_4_0.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Copy the data to have a consistent naming with the .py file</span> +<span class="n">zlist</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">hz</span><span class="p">)</span> +<span class="n">x_opt</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">hxDR</span><span class="p">)</span> +<span class="n">xlist</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">hxDR</span><span class="p">)</span> +<span class="n">number_of_nodes</span> <span class="o">=</span> <span class="n">x_opt</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> +<span class="n">n</span> <span class="o">=</span> <span class="n">number_of_nodes</span> <span class="o">*</span> <span class="n">STATE_SIZE</span> +</pre></div> +</div> +<p>After the data has been saved, the graph will be constructed by looking +at each pair for nodes. The virtual measurement is only created if two +nodes have observed the same landmark at different points in time. The +next cells are a walk through for a single iteration of graph +construction -> optimization -> estimate update.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># get all the possible combination of the different node</span> +<span class="n">zids</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">combinations</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">zlist</span><span class="p">)),</span> <span class="mi">2</span><span class="p">))</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Node combinations: </span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">zids</span><span class="p">)</span> + +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">xlist</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"Node </span><span class="si">{}</span><span class="s2"> observed landmark with ID </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">zlist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">]))</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Node</span> <span class="n">combinations</span><span class="p">:</span> + <span class="p">[(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span> +<span class="n">Node</span> <span class="mi">0</span> <span class="n">observed</span> <span class="n">landmark</span> <span class="k">with</span> <span class="n">ID</span> <span class="mf">0.0</span> +<span class="n">Node</span> <span class="mi">1</span> <span class="n">observed</span> <span class="n">landmark</span> <span class="k">with</span> <span class="n">ID</span> <span class="mf">0.0</span> +</pre></div> +</div> +<p>In the following code snippet the error based on the virtual measurement +between node 0 and 1 will be created. The equations for the error is as follows: +<span class="math notranslate nohighlight">\(e_{ij}^x = x_j + d_j cos(\psi_j +\theta_j) - x_i - d_i cos(\psi_i + \theta_i)\)</span></p> +<p><span class="math notranslate nohighlight">\(e_{ij}^y = y_j + d_j sin(\psi_j + \theta_j) - y_i - d_i sin(\psi_i + \theta_i)\)</span></p> +<p><span class="math notranslate nohighlight">\(e_{ij}^x = \psi_j + \theta_j - \psi_i - \theta_i\)</span></p> +<p>Where <span class="math notranslate nohighlight">\([x_i, y_i, \psi_i]\)</span> is the pose for node <span class="math notranslate nohighlight">\(i\)</span> and +similarly for node <span class="math notranslate nohighlight">\(j\)</span>, <span class="math notranslate nohighlight">\(d\)</span> is the measured distance at +nodes <span class="math notranslate nohighlight">\(i\)</span> and <span class="math notranslate nohighlight">\(j\)</span>, and <span class="math notranslate nohighlight">\(\theta\)</span> is the measured +bearing to the landmark. The difference is visualized with the figure in +the next cell.</p> +<p>In case of perfect motion and perfect measurement the error shall be +zero since <span class="math notranslate nohighlight">\(x_j + d_j cos(\psi_j + \theta_j)\)</span> should equal +<span class="math notranslate nohighlight">\(x_i + d_i cos(\psi_i + \theta_i)\)</span></p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Initialize edges list</span> +<span class="n">edges</span> <span class="o">=</span> <span class="p">[]</span> + +<span class="c1"># Go through all the different combinations</span> +<span class="k">for</span> <span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">)</span> <span class="ow">in</span> <span class="n">zids</span><span class="p">:</span> + <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">yaw1</span> <span class="o">=</span> <span class="n">xlist</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">t1</span><span class="p">],</span> <span class="n">xlist</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">t1</span><span class="p">],</span> <span class="n">xlist</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="n">t1</span><span class="p">]</span> + <span class="n">x2</span><span class="p">,</span> <span class="n">y2</span><span class="p">,</span> <span class="n">yaw2</span> <span class="o">=</span> <span class="n">xlist</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">t2</span><span class="p">],</span> <span class="n">xlist</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="n">t2</span><span class="p">],</span> <span class="n">xlist</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="n">t2</span><span class="p">]</span> + + <span class="c1"># All nodes have valid observation with ID=0, therefore, no data association condition</span> + <span class="n">iz1</span> <span class="o">=</span> <span class="mi">0</span> + <span class="n">iz2</span> <span class="o">=</span> <span class="mi">0</span> + + <span class="n">d1</span> <span class="o">=</span> <span class="n">zlist</span><span class="p">[</span><span class="n">t1</span><span class="p">][</span><span class="n">iz1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">angle1</span><span class="p">,</span> <span class="n">phi1</span> <span class="o">=</span> <span class="n">zlist</span><span class="p">[</span><span class="n">t1</span><span class="p">][</span><span class="n">iz1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">zlist</span><span class="p">[</span><span class="n">t1</span><span class="p">][</span><span class="n">iz1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> + <span class="n">d2</span> <span class="o">=</span> <span class="n">zlist</span><span class="p">[</span><span class="n">t2</span><span class="p">][</span><span class="n">iz2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> + <span class="n">angle2</span><span class="p">,</span> <span class="n">phi2</span> <span class="o">=</span> <span class="n">zlist</span><span class="p">[</span><span class="n">t2</span><span class="p">][</span><span class="n">iz2</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">zlist</span><span class="p">[</span><span class="n">t2</span><span class="p">][</span><span class="n">iz2</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> + + <span class="c1"># find angle between observation and horizontal</span> + <span class="n">tangle1</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">yaw1</span> <span class="o">+</span> <span class="n">angle1</span><span class="p">)</span> + <span class="n">tangle2</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">yaw2</span> <span class="o">+</span> <span class="n">angle2</span><span class="p">)</span> + + <span class="c1"># project the observations</span> + <span class="n">tmp1</span> <span class="o">=</span> <span class="n">d1</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">tangle1</span><span class="p">)</span> + <span class="n">tmp2</span> <span class="o">=</span> <span class="n">d2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">tangle2</span><span class="p">)</span> + <span class="n">tmp3</span> <span class="o">=</span> <span class="n">d1</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">tangle1</span><span class="p">)</span> + <span class="n">tmp4</span> <span class="o">=</span> <span class="n">d2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">tangle2</span><span class="p">)</span> + + <span class="n">edge</span> <span class="o">=</span> <span class="n">Edge</span><span class="p">()</span> + <span class="nb">print</span><span class="p">(</span><span class="n">y1</span><span class="p">,</span><span class="n">y2</span><span class="p">,</span> <span class="n">tmp3</span><span class="p">,</span> <span class="n">tmp4</span><span class="p">)</span> + <span class="c1"># calculate the error of the virtual measurement</span> + <span class="c1"># node 1 as seen from node 2 throught the observations 1,2</span> + <span class="n">edge</span><span class="o">.</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">x2</span> <span class="o">-</span> <span class="n">x1</span> <span class="o">-</span> <span class="n">tmp1</span> <span class="o">+</span> <span class="n">tmp2</span> + <span class="n">edge</span><span class="o">.</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">y2</span> <span class="o">-</span> <span class="n">y1</span> <span class="o">-</span> <span class="n">tmp3</span> <span class="o">+</span> <span class="n">tmp4</span> + <span class="n">edge</span><span class="o">.</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">pi_2_pi</span><span class="p">(</span><span class="n">yaw2</span> <span class="o">-</span> <span class="n">yaw1</span> <span class="o">-</span> <span class="n">tangle1</span> <span class="o">+</span> <span class="n">tangle2</span><span class="p">)</span> + + <span class="n">edge</span><span class="o">.</span><span class="n">d1</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">d2</span> <span class="o">=</span> <span class="n">d1</span><span class="p">,</span> <span class="n">d2</span> + <span class="n">edge</span><span class="o">.</span><span class="n">yaw1</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">yaw2</span> <span class="o">=</span> <span class="n">yaw1</span><span class="p">,</span> <span class="n">yaw2</span> + <span class="n">edge</span><span class="o">.</span><span class="n">angle1</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">angle2</span> <span class="o">=</span> <span class="n">angle1</span><span class="p">,</span> <span class="n">angle2</span> + <span class="n">edge</span><span class="o">.</span><span class="n">id1</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">id2</span> <span class="o">=</span> <span class="n">t1</span><span class="p">,</span> <span class="n">t2</span> + + <span class="n">edges</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">edge</span><span class="p">)</span> + + <span class="nb">print</span><span class="p">(</span><span class="s2">"For nodes"</span><span class="p">,(</span><span class="n">t1</span><span class="p">,</span><span class="n">t2</span><span class="p">))</span> + <span class="nb">print</span><span class="p">(</span><span class="s2">"Added edge with errors: </span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">e</span><span class="p">)</span> + + <span class="c1"># Visualize measurement projections</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">RFID</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">RFID</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="s2">"*k"</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x1</span><span class="p">,</span><span class="n">x2</span><span class="p">],[</span><span class="n">y1</span><span class="p">,</span><span class="n">y2</span><span class="p">],</span> <span class="s1">'.'</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x1</span><span class="p">,</span> <span class="n">x1</span> <span class="o">+</span> <span class="n">graphics_radius</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">yaw1</span><span class="p">)],</span> + <span class="p">[</span><span class="n">y1</span><span class="p">,</span> <span class="n">y1</span> <span class="o">+</span> <span class="n">graphics_radius</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">yaw1</span><span class="p">)],</span> <span class="s1">'r'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x2</span><span class="p">,</span> <span class="n">x2</span> <span class="o">+</span> <span class="n">graphics_radius</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">yaw2</span><span class="p">)],</span> + <span class="p">[</span><span class="n">y2</span><span class="p">,</span> <span class="n">y2</span> <span class="o">+</span> <span class="n">graphics_radius</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">yaw2</span><span class="p">)],</span> <span class="s1">'r'</span><span class="p">)</span> + + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x1</span><span class="p">,</span><span class="n">x1</span><span class="o">+</span><span class="n">tmp1</span><span class="p">],</span> <span class="p">[</span><span class="n">y1</span><span class="p">,</span><span class="n">y1</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="s2">"obs 1 x"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x2</span><span class="p">,</span><span class="n">x2</span><span class="o">+</span><span class="n">tmp2</span><span class="p">],</span> <span class="p">[</span><span class="n">y2</span><span class="p">,</span><span class="n">y2</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="s2">"obs 2 x"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x1</span><span class="p">,</span><span class="n">x1</span><span class="p">],</span> <span class="p">[</span><span class="n">y1</span><span class="p">,</span><span class="n">y1</span><span class="o">+</span><span class="n">tmp3</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="s2">"obs 1 y"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x2</span><span class="p">,</span><span class="n">x2</span><span class="p">],</span> <span class="p">[</span><span class="n">y2</span><span class="p">,</span><span class="n">y2</span><span class="o">+</span><span class="n">tmp4</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="s2">"obs 2 y"</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x1</span><span class="o">+</span><span class="n">tmp1</span><span class="p">,</span> <span class="n">y1</span><span class="o">+</span><span class="n">tmp3</span><span class="p">,</span> <span class="s1">'o'</span><span class="p">)</span> + <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x2</span><span class="o">+</span><span class="n">tmp2</span><span class="p">,</span> <span class="n">y2</span><span class="o">+</span><span class="n">tmp4</span><span class="p">,</span> <span class="s1">'o'</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">0.0</span> <span class="mf">1.427649841628278</span> <span class="o">-</span><span class="mf">2.0126109674819155</span> <span class="o">-</span><span class="mf">3.524048014922737</span> +<span class="n">For</span> <span class="n">nodes</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> +<span class="n">Added</span> <span class="n">edge</span> <span class="k">with</span> <span class="n">errors</span><span class="p">:</span> + <span class="p">[[</span><span class="o">-</span><span class="mf">0.02</span> <span class="p">]</span> + <span class="p">[</span><span class="o">-</span><span class="mf">0.084</span><span class="p">]</span> + <span class="p">[</span> <span class="mf">0.</span> <span class="p">]]</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_doc_9_1.png" src="../../../_images/graphSLAM_doc_9_1.png" /> +<p>Since the constraints equations derived before are non-linear, +linearization is needed before we can insert them into the information +matrix and information vector. Two jacobians</p> +<p><span class="math notranslate nohighlight">\(A = \frac{\partial e_{ij}}{\partial \boldsymbol{x}_i}\)</span> as +<span class="math notranslate nohighlight">\(\boldsymbol{x}_i\)</span> holds the three variabls x, y, and theta. +Similarly, <span class="math notranslate nohighlight">\(B = \frac{\partial e_{ij}}{\partial \boldsymbol{x}_j}\)</span></p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Initialize the system information matrix and information vector</span> +<span class="n">H</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">n</span><span class="p">,</span> <span class="n">n</span><span class="p">))</span> +<span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> +<span class="n">x_opt</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">hxDR</span><span class="p">)</span> + +<span class="k">for</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">edges</span><span class="p">:</span> + <span class="n">id1</span> <span class="o">=</span> <span class="n">edge</span><span class="o">.</span><span class="n">id1</span> <span class="o">*</span> <span class="n">STATE_SIZE</span> + <span class="n">id2</span> <span class="o">=</span> <span class="n">edge</span><span class="o">.</span><span class="n">id2</span> <span class="o">*</span> <span class="n">STATE_SIZE</span> + + <span class="n">t1</span> <span class="o">=</span> <span class="n">edge</span><span class="o">.</span><span class="n">yaw1</span> <span class="o">+</span> <span class="n">edge</span><span class="o">.</span><span class="n">angle1</span> + <span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">d1</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">t1</span><span class="p">)],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="o">-</span><span class="n">edge</span><span class="o">.</span><span class="n">d1</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">t1</span><span class="p">)],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">]])</span> + + <span class="n">t2</span> <span class="o">=</span> <span class="n">edge</span><span class="o">.</span><span class="n">yaw2</span> <span class="o">+</span> <span class="n">edge</span><span class="o">.</span><span class="n">angle2</span> + <span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">edge</span><span class="o">.</span><span class="n">d2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">t2</span><span class="p">)],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="n">edge</span><span class="o">.</span><span class="n">d2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">t2</span><span class="p">)],</span> + <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]])</span> + + <span class="c1"># TODO: use Qsim instead of sigma</span> + <span class="n">sigma</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">diag</span><span class="p">([</span><span class="n">C_SIGMA1</span><span class="p">,</span> <span class="n">C_SIGMA2</span><span class="p">,</span> <span class="n">C_SIGMA3</span><span class="p">])</span> + <span class="n">Rt1</span> <span class="o">=</span> <span class="n">calc_rotational_matrix</span><span class="p">(</span><span class="n">tangle1</span><span class="p">)</span> + <span class="n">Rt2</span> <span class="o">=</span> <span class="n">calc_rotational_matrix</span><span class="p">(</span><span class="n">tangle2</span><span class="p">)</span> + <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">Rt1</span> <span class="o">@</span> <span class="n">sigma</span> <span class="o">@</span> <span class="n">Rt1</span><span class="o">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">Rt2</span> <span class="o">@</span> <span class="n">sigma</span> <span class="o">@</span> <span class="n">Rt2</span><span class="o">.</span><span class="n">T</span><span class="p">)</span> + + <span class="c1"># Fill in entries in H and b</span> + <span class="n">H</span><span class="p">[</span><span class="n">id1</span><span class="p">:</span><span class="n">id1</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">,</span> <span class="n">id1</span><span class="p">:</span><span class="n">id1</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="n">A</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">@</span> <span class="n">A</span> + <span class="n">H</span><span class="p">[</span><span class="n">id1</span><span class="p">:</span><span class="n">id1</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">,</span> <span class="n">id2</span><span class="p">:</span><span class="n">id2</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="n">A</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">@</span> <span class="n">B</span> + <span class="n">H</span><span class="p">[</span><span class="n">id2</span><span class="p">:</span><span class="n">id2</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">,</span> <span class="n">id1</span><span class="p">:</span><span class="n">id1</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="n">B</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">@</span> <span class="n">A</span> + <span class="n">H</span><span class="p">[</span><span class="n">id2</span><span class="p">:</span><span class="n">id2</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">,</span> <span class="n">id2</span><span class="p">:</span><span class="n">id2</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="n">B</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">@</span> <span class="n">B</span> + + <span class="n">b</span><span class="p">[</span><span class="n">id1</span><span class="p">:</span><span class="n">id1</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="p">(</span><span class="n">A</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">e</span><span class="p">)</span> + <span class="n">b</span><span class="p">[</span><span class="n">id2</span><span class="p">:</span><span class="n">id2</span> <span class="o">+</span> <span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="p">(</span><span class="n">B</span><span class="o">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">omega</span> <span class="o">@</span> <span class="n">edge</span><span class="o">.</span><span class="n">e</span><span class="p">)</span> + + +<span class="nb">print</span><span class="p">(</span><span class="s2">"The determinant of H: "</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">det</span><span class="p">(</span><span class="n">H</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">H</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">])</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">])</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> + +<span class="c1"># Fix the origin, multiply by large number gives same results but better visualization</span> +<span class="n">H</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">STATE_SIZE</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span><span class="n">STATE_SIZE</span><span class="p">]</span> <span class="o">+=</span> <span class="n">np</span><span class="o">.</span><span class="n">identity</span><span class="p">(</span><span class="n">STATE_SIZE</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"The determinant of H after origin constraint: "</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">det</span><span class="p">(</span><span class="n">H</span><span class="p">))</span> +<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">H</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">])</span> +<span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> +<span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span><span class="p">])</span> +<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">The</span> <span class="n">determinant</span> <span class="n">of</span> <span class="n">H</span><span class="p">:</span> <span class="mf">0.0</span> +<span class="n">The</span> <span class="n">determinant</span> <span class="n">of</span> <span class="n">H</span> <span class="n">after</span> <span class="n">origin</span> <span class="n">constraint</span><span class="p">:</span> <span class="mf">716.1972439134893</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_doc_11_1.png" src="../../../_images/graphSLAM_doc_11_1.png" /> +<img alt="../../../_images/graphSLAM_doc_11_2.png" src="../../../_images/graphSLAM_doc_11_2.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Find the solution (first iteration)</span> +<span class="n">dx</span> <span class="o">=</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">H</span><span class="p">)</span> <span class="o">@</span> <span class="n">b</span> +<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number_of_nodes</span><span class="p">):</span> + <span class="n">x_opt</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">3</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="n">dx</span><span class="p">[</span><span class="n">i</span> <span class="o">*</span> <span class="mi">3</span><span class="p">:</span><span class="n">i</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"dx: </span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span><span class="n">dx</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"ground truth: </span><span class="se">\n</span><span class="s2"> "</span><span class="p">,</span><span class="n">hxTrue</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Odom: </span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">hxDR</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"SLAM: </span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">x_opt</span><span class="p">)</span> + +<span class="c1"># performance will improve with more iterations, nodes and landmarks.</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">graphSLAM localization error: "</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">((</span><span class="n">x_opt</span> <span class="o">-</span> <span class="n">hxTrue</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">))</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Odom localization error: "</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">((</span><span class="n">hxDR</span> <span class="o">-</span> <span class="n">hxTrue</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span><span class="p">))</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">dx</span><span class="p">:</span> + <span class="p">[[</span><span class="o">-</span><span class="mf">0.</span> <span class="p">]</span> + <span class="p">[</span><span class="o">-</span><span class="mf">0.</span> <span class="p">]</span> + <span class="p">[</span> <span class="mf">0.</span> <span class="p">]</span> + <span class="p">[</span> <span class="mf">0.02</span> <span class="p">]</span> + <span class="p">[</span> <span class="mf">0.084</span><span class="p">]</span> + <span class="p">[</span><span class="o">-</span><span class="mf">0.</span> <span class="p">]]</span> +<span class="n">ground</span> <span class="n">truth</span><span class="p">:</span> + <span class="p">[[</span><span class="mf">0.</span> <span class="mf">1.414</span><span class="p">]</span> + <span class="p">[</span><span class="mf">0.</span> <span class="mf">1.414</span><span class="p">]</span> + <span class="p">[</span><span class="mf">0.785</span> <span class="mf">0.985</span><span class="p">]]</span> +<span class="n">Odom</span><span class="p">:</span> + <span class="p">[[</span><span class="mf">0.</span> <span class="mf">1.428</span><span class="p">]</span> + <span class="p">[</span><span class="mf">0.</span> <span class="mf">1.428</span><span class="p">]</span> + <span class="p">[</span><span class="mf">0.785</span> <span class="mf">0.976</span><span class="p">]]</span> +<span class="n">SLAM</span><span class="p">:</span> + <span class="p">[[</span><span class="o">-</span><span class="mf">0.</span> <span class="mf">1.448</span><span class="p">]</span> + <span class="p">[</span><span class="o">-</span><span class="mf">0.</span> <span class="mf">1.512</span><span class="p">]</span> + <span class="p">[</span> <span class="mf">0.785</span> <span class="mf">0.976</span><span class="p">]]</span> + +<span class="n">graphSLAM</span> <span class="n">localization</span> <span class="n">error</span><span class="p">:</span> <span class="mf">0.010729072751057656</span> +<span class="n">Odom</span> <span class="n">localization</span> <span class="n">error</span><span class="p">:</span> <span class="mf">0.0004460978857535104</span> +</pre></div> +</div> +</section> +<section id="the-references"> +<h3>The references:<a class="headerlink" href="#the-references" title="Permalink to this headline"></a></h3> +<ul class="simple"> +<li><p><a class="reference external" href="http://robots.stanford.edu/papers/thrun.graphslam.pdf">The GraphSLAM Algorithm with Applications to Large-Scale Mapping of Urban Structures</a></p></li> +<li><p><a class="reference external" href="http://ais.informatik.uni-freiburg.de/teaching/ss13/robotics/slides/16-graph-slam.pdf">Introduction to Mobile Robotics Graph-Based SLAM</a></p></li> +<li><p><a class="reference external" href="http://www2.informatik.uni-freiburg.de/~stachnis/pdf/grisetti10titsmag.pdf">A Tutorial on Graph-Based SLAM</a></p></li> +</ul> +<p>N.B. An additional step is required that uses the estimated path to +update the belief regarding the map.</p> +</section> +</section> +<section id="graph-slam-formulation"> +<span id="id1"></span><h2>Graph SLAM Formulation<a class="headerlink" href="#graph-slam-formulation" title="Permalink to this headline"></a></h2> +<p>Author Jeff Irion</p> +<section id="problem-formulation"> +<h3>Problem Formulation<a class="headerlink" href="#problem-formulation" title="Permalink to this headline"></a></h3> +<p>Let a robot’s trajectory through its environment be represented by a +sequence of <span class="math notranslate nohighlight">\(N\)</span> poses: +<span class="math notranslate nohighlight">\(\mathbf{p}_1, \mathbf{p}_2, \ldots, \mathbf{p}_N\)</span>. Each pose lies +on a manifold: <span class="math notranslate nohighlight">\(\mathbf{p}_i \in \mathcal{M}\)</span>. Simple examples of +manifolds used in Graph SLAM include 1-D, 2-D, and 3-D space, i.e., +<span class="math notranslate nohighlight">\(\mathbb{R}\)</span>, <span class="math notranslate nohighlight">\(\mathbb{R}^2\)</span>, and <span class="math notranslate nohighlight">\(\mathbb{R}^3\)</span>. +These environments are <em>rectilinear</em>, meaning that there is no concept +of orientation. By contrast, in <span class="math notranslate nohighlight">\(SE(2)\)</span> problem settings a robot’s +pose consists of its location in <span class="math notranslate nohighlight">\(\mathbb{R}^2\)</span> and its +orientation <span class="math notranslate nohighlight">\(\theta\)</span>. Similarly, in <span class="math notranslate nohighlight">\(SE(3)\)</span> a robot’s pose +consists of its location in <span class="math notranslate nohighlight">\(\mathbb{R}^3\)</span> and its orientation, +which can be represented via Euler angles, quaternions, or <span class="math notranslate nohighlight">\(SO(3)\)</span> +rotation matrices.</p> +<p>As the robot explores its environment, it collects a set of <span class="math notranslate nohighlight">\(M\)</span> +measurements <span class="math notranslate nohighlight">\(\mathcal{Z} = \{\mathbf{z}_j\}\)</span>. Examples of such +measurements include odometry, GPS, and IMU data. Given a set of poses +<span class="math notranslate nohighlight">\(\mathbf{p}_1, \ldots, \mathbf{p}_N\)</span>, we can compute the estimated +measurement +<span class="math notranslate nohighlight">\(\hat{\mathbf{z}}_j(\mathbf{p}_1, \ldots, \mathbf{p}_N)\)</span>. We can +then compute the <em>residual</em> +<span class="math notranslate nohighlight">\(\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j)\)</span> for measurement +<span class="math notranslate nohighlight">\(j\)</span>. The formula for the residual depends on the type of +measurement. As an example, let <span class="math notranslate nohighlight">\(\mathbf{z}_1\)</span> be an odometry +measurement that was collected when the robot traveled from +<span class="math notranslate nohighlight">\(\mathbf{p}_1\)</span> to <span class="math notranslate nohighlight">\(\mathbf{p}_2\)</span>. The expected measurement +and the residual are computed as</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} + \hat{\mathbf{z}}_1(\mathbf{p}_1, \mathbf{p}_2) &= \mathbf{p}_2 \ominus \mathbf{p}_1 \\ + \mathbf{e}_1(\mathbf{z}_1, \hat{\mathbf{z}}_1) &= \mathbf{z}_1 \ominus \hat{\mathbf{z}}_1 = \mathbf{z}_1 \ominus (\mathbf{p}_2 \ominus \mathbf{p}_1),\end{aligned}\end{split}\]</div> +<p>where the <span class="math notranslate nohighlight">\(\ominus\)</span> operator indicates inverse pose composition. +We model measurement <span class="math notranslate nohighlight">\(\mathbf{z}_j\)</span> as having independent Gaussian +noise with zero mean and covariance matrix <span class="math notranslate nohighlight">\(\Omega_j^{-1}\)</span>; we +refer to <span class="math notranslate nohighlight">\(\Omega_j\)</span> as the <em>information matrix</em> for measurement +<span class="math notranslate nohighlight">\(j\)</span>. That is,</p> +<div class="math notranslate nohighlight" id="equation-infomat"> +<span class="eqno">(1)<a class="headerlink" href="#equation-infomat" title="Permalink to this equation"></a></span>\[p(\mathbf{z}_j \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) = \eta_j \exp (-\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\mathsf{T}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j)\]</div> +<p>where <span class="math notranslate nohighlight">\(\eta_j\)</span> is the normalization constant.</p> +<p>The objective of Graph SLAM is to find the maximum likelihood set of +poses given the measurements <span class="math notranslate nohighlight">\(\mathcal{Z} = \{\mathbf{z}_j\}\)</span>; in +other words, we want to find</p> +<div class="math notranslate nohighlight"> +\[\mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \ p(\mathbf{p}_1, \ldots, \mathbf{p}_N \ | \ \mathcal{Z})\]</div> +<p>Using Bayes’ rule, we can write this probability as</p> +<div class="math notranslate nohighlight" id="equation-bayes"> +<span class="eqno">(2)<a class="headerlink" href="#equation-bayes" title="Permalink to this equation"></a></span>\[\begin{split}\begin{aligned} + p(\mathbf{p}_1, \ldots, \mathbf{p}_N \ | \ \mathcal{Z}) &= \frac{p( \mathcal{Z} \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) p(\mathbf{p}_1, \ldots, \mathbf{p}_N) }{ p(\mathcal{Z}) } \notag \\ + &\propto p( \mathcal{Z} \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) +\end{aligned}\end{split}\]</div> +<p>since <span class="math notranslate nohighlight">\(p(\mathcal{Z})\)</span> is a constant (albeit, an unknown constant) +and we assume that <span class="math notranslate nohighlight">\(p(\mathbf{p}_1, \ldots, \mathbf{p}_N)\)</span> is +uniformly distributed. Therefore, we +can use Eq. <a class="reference internal" href="#equation-infomat">(1)</a> and and Eq. <a class="reference internal" href="#equation-bayes">(2)</a> to simplify the Graph SLAM +optimization as follows:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} + \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \ p(\mathbf{p}_1, \ldots, \mathbf{p}_N \ | \ \mathcal{Z}) &= \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \ p( \mathcal{Z} \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) \\ + &= \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \prod_{j=1}^M p(\mathbf{z}_j \ | \ \mathbf{p}_1, \ldots, \mathbf{p}_N) \\ + &= \mathop{\mathrm{arg\,max}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \prod_{j=1}^M \exp \left( -(\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j) \right) \\ + &= \mathop{\mathrm{arg\,min}}_{\mathbf{p}_1, \ldots, \mathbf{p}_N} \sum_{j=1}^M (\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j).\end{aligned}\end{split}\]</div> +<p>We define</p> +<div class="math notranslate nohighlight"> +\[\chi^2 := \sum_{j=1}^M (\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j))^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j),\]</div> +<p>and this is what we seek to minimize.</p> +</section> +<section id="dimensionality-and-pose-representation"> +<h3>Dimensionality and Pose Representation<a class="headerlink" href="#dimensionality-and-pose-representation" title="Permalink to this headline"></a></h3> +<p>Before proceeding further, it is helpful to discuss the dimensionality +of the problem. We have:</p> +<ul class="simple"> +<li><p>A set of <span class="math notranslate nohighlight">\(N\)</span> poses +<span class="math notranslate nohighlight">\(\mathbf{p}_1, \mathbf{p}_2, \ldots, \mathbf{p}_N\)</span>, where each +pose lies on the manifold <span class="math notranslate nohighlight">\(\mathcal{M}\)</span></p> +<ul> +<li><p>Each pose <span class="math notranslate nohighlight">\(\mathbf{p}_i\)</span> is represented as a vector in (a +subset of) <span class="math notranslate nohighlight">\(\mathbb{R}^d\)</span>. For example:</p> +<ul> +<li><p>An <span class="math notranslate nohighlight">\(SE(2)\)</span> pose is typically represented as +<span class="math notranslate nohighlight">\((x, y, \theta)\)</span>, and thus <span class="math notranslate nohighlight">\(d = 3\)</span>.</p></li> +<li><p>An <span class="math notranslate nohighlight">\(SE(3)\)</span> pose is typically represented as +<span class="math notranslate nohighlight">\((x, y, z, q_x, q_y, q_z, q_w)\)</span>, where <span class="math notranslate nohighlight">\((x, y, z)\)</span> +is a point in <span class="math notranslate nohighlight">\(\mathbb{R}^3\)</span> and +<span class="math notranslate nohighlight">\((q_x, q_y, q_z, q_w)\)</span> is a <em>quaternion</em>, and so +<span class="math notranslate nohighlight">\(d = 7\)</span>. For more information about <span class="math notranslate nohighlight">\(SE(3)\)</span> +parameterization and pose transformations, see +<a class="reference internal" href="#blanco2010tutorial" id="id2"><span>[blanco2010tutorial]</span></a>.</p></li> +</ul> +</li> +<li><p>We also need to be able to represent each pose compactly as a +vector in (a subset of) <span class="math notranslate nohighlight">\(\mathbb{R}^c\)</span>.</p> +<ul> +<li><p>Since an <span class="math notranslate nohighlight">\(SE(2)\)</span> pose has three degrees of freedom, the +<span class="math notranslate nohighlight">\((x, y, \theta)\)</span> representation is again sufficient and +<span class="math notranslate nohighlight">\(c=3\)</span>.</p></li> +<li><p>An <span class="math notranslate nohighlight">\(SE(3)\)</span> pose only has six degrees of freedom, and we +can represent it compactly as <span class="math notranslate nohighlight">\((x, y, z, q_x, q_y, q_z)\)</span>, +and thus <span class="math notranslate nohighlight">\(c=6\)</span>.</p></li> +</ul> +</li> +<li><p>We use the <span class="math notranslate nohighlight">\(\boxplus\)</span> operator to indicate pose composition +when one or both of the poses are represented compactly. The +output can be a pose in <span class="math notranslate nohighlight">\(\mathcal{M}\)</span> or a vector in +<span class="math notranslate nohighlight">\(\mathbb{R}^c\)</span>, as required by context.</p></li> +</ul> +</li> +<li><p>A set of <span class="math notranslate nohighlight">\(M\)</span> measurements +<span class="math notranslate nohighlight">\(\mathcal{Z} = \{\mathbf{z}_1, \mathbf{z}_2, \ldots, \mathbf{z}_M\}\)</span></p> +<ul> +<li><p>Each measurement’s dimensionality can be unique, and we will use +<span class="math notranslate nohighlight">\(\bullet\)</span> to denote a “wildcard” variable.</p></li> +<li><p>Measurement <span class="math notranslate nohighlight">\(\mathbf{z}_j \in \mathbb{R}^\bullet\)</span> has an +associated information matrix +<span class="math notranslate nohighlight">\(\Omega_j \in \mathbb{R}^{\bullet \times \bullet}\)</span> and +residual function +<span class="math notranslate nohighlight">\(\mathbf{e}_j(\mathbf{z}_j, \hat{\mathbf{z}}_j) = \mathbf{e}_j(\mathbf{z}_j, \mathbf{p}_1, \ldots, \mathbf{p}_N) \in \mathbb{R}^\bullet\)</span>.</p></li> +<li><p>A measurement could, in theory, constrain anywhere from 1 pose to +all <span class="math notranslate nohighlight">\(N\)</span> poses. In practice, each measurement usually +constrains only 1 or 2 poses.</p></li> +</ul> +</li> +</ul> +</section> +<section id="graph-slam-algorithm"> +<h3>Graph SLAM Algorithm<a class="headerlink" href="#graph-slam-algorithm" title="Permalink to this headline"></a></h3> +<p>The “Graph” in Graph SLAM refers to the fact that we view the problem as +a graph. The graph has a set <span class="math notranslate nohighlight">\(\mathcal{V}\)</span> of <span class="math notranslate nohighlight">\(N\)</span> vertices, +where each vertex <span class="math notranslate nohighlight">\(v_i\)</span> has an associated pose +<span class="math notranslate nohighlight">\(\mathbf{p}_i\)</span>. Similarly, the graph has a set <span class="math notranslate nohighlight">\(\mathcal{E}\)</span> +of <span class="math notranslate nohighlight">\(M\)</span> edges, where each edge <span class="math notranslate nohighlight">\(e_j\)</span> has an associated +measurement <span class="math notranslate nohighlight">\(\mathbf{z}_j\)</span>. In practice, the edges in this graph +are either unary (i.e., a loop) or binary. (Note: <span class="math notranslate nohighlight">\(e_j\)</span> refers to +the edge in the graph associated with measurement <span class="math notranslate nohighlight">\(\mathbf{z}_j\)</span>, +whereas <span class="math notranslate nohighlight">\(\mathbf{e}_j\)</span> refers to the residual function associated +with <span class="math notranslate nohighlight">\(\mathbf{z}_j\)</span>.) For more information about the Graph SLAM +algorithm, see <a class="reference internal" href="#grisetti2010tutorial" id="id3"><span>[grisetti2010tutorial]</span></a>.</p> +<p>We want to optimize</p> +<div class="math notranslate nohighlight"> +\[\chi^2 = \sum_{e_j \in \mathcal{E}} \mathbf{e}_j^{\scriptstyle{\mathsf{T}}}\Omega_j \mathbf{e}_j.\]</div> +<p>Let <span class="math notranslate nohighlight">\(\mathbf{x}_i \in \mathbb{R}^c\)</span> be the compact representation +of pose <span class="math notranslate nohighlight">\(\mathbf{p}_i \in \mathcal{M}\)</span>, and let</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\mathbf{x} := \begin{bmatrix} \mathbf{x}_1 \\ \mathbf{x}_2 \\ \vdots \\ \mathbf{x}_N \end{bmatrix} \in \mathbb{R}^{cN}\end{split}\]</div> +<p>We will solve this optimization problem iteratively. Let</p> +<div class="math notranslate nohighlight" id="equation-update"> +<span class="eqno">(3)<a class="headerlink" href="#equation-update" title="Permalink to this equation"></a></span>\[\begin{split}\mathbf{x}^{k+1} := \mathbf{x}^k \boxplus \Delta \mathbf{x}^k = \begin{bmatrix} \mathbf{x}_1 \boxplus \Delta \mathbf{x}_1 \\ \mathbf{x}_2 \boxplus \Delta \mathbf{x}_2 \\ \vdots \\ \mathbf{x}_N \boxplus \Delta \mathbf{x}_2 \end{bmatrix}\end{split}\]</div> +<p>The <span class="math notranslate nohighlight">\(\chi^2\)</span> error at iteration <span class="math notranslate nohighlight">\(k+1\)</span> is</p> +<div class="math notranslate nohighlight" id="equation-chisq-at-kplusone"> +<span class="eqno">(4)<a class="headerlink" href="#equation-chisq-at-kplusone" title="Permalink to this equation"></a></span>\[\chi_{k+1}^2 = \sum_{e_j \in \mathcal{E}} \underbrace{\left[ \mathbf{e}_j(\mathbf{x}^{k+1}) \right]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\mathbf{e}_j(\mathbf{x}^{k+1})}_{\bullet \times 1}.\]</div> +<p>We will linearize the residuals as:</p> +<div class="math notranslate nohighlight" id="equation-linearization"> +<span class="eqno">(5)<a class="headerlink" href="#equation-linearization" title="Permalink to this equation"></a></span>\[\begin{split}\begin{aligned} + \mathbf{e}_j(\mathbf{x}^{k+1}) &= \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k) \\ + &\approx \mathbf{e}_j(\mathbf{x}^{k}) + \frac{\partial}{\partial \Delta \mathbf{x}^k} \left[ \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k) \right] \Delta \mathbf{x}^k \\ + &= \mathbf{e}_j(\mathbf{x}^{k}) + \left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right) \frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k} \Delta \mathbf{x}^k. +\end{aligned}\end{split}\]</div> +<p>Plugging <a class="reference internal" href="#equation-linearization">(5)</a> into <a class="reference internal" href="#equation-chisq-at-kplusone">(4)</a>, we get:</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} + \chi_{k+1}^2 &\approx \ \ \ \ \ \sum_{e_j \in \mathcal{E}} \underbrace{[ \mathbf{e}_j(\mathbf{x}^k)]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\mathbf{e}_j(\mathbf{x}^k)}_{\bullet \times 1} \notag \\ + &\hphantom{\approx} \ \ \ + \sum_{e_j \in \mathcal{E}} \underbrace{[ \mathbf{e}_j(\mathbf{x^k}) ]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN} \underbrace{\Delta \mathbf{x}^k}_{cN \times 1} \notag \\ + &\hphantom{\approx} \ \ \ + \sum_{e_j \in \mathcal{E}} \underbrace{(\Delta \mathbf{x}^k)^{\scriptstyle{\mathsf{T}}}}_{1 \times cN} \underbrace{ \left( \frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k} \right)^{\scriptstyle{\mathsf{T}}}}_{cN \times dN} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)^{\scriptstyle{\mathsf{T}}}}_{dN \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN} \underbrace{\Delta \mathbf{x}^k}_{cN \times 1} \notag \\ + &= \chi_k^2 + 2 \mathbf{b}^{\scriptstyle{\mathsf{T}}}\Delta \mathbf{x}^k + (\Delta \mathbf{x}^k)^{\scriptstyle{\mathsf{T}}}H \Delta \mathbf{x}^k, \notag\end{aligned}\end{split}\]</div> +<p>where</p> +<div class="math notranslate nohighlight"> +\[\begin{split}\begin{aligned} + \mathbf{b}^{\scriptstyle{\mathsf{T}}}&= \sum_{e_j \in \mathcal{E}} \underbrace{[ \mathbf{e}_j(\mathbf{x^k}) ]^{\scriptstyle{\mathsf{T}}}}_{1 \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN} \\ + H &= \sum_{e_j \in \mathcal{E}} \underbrace{ \left( \frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k} \right)^{\scriptstyle{\mathsf{T}}}}_{cN \times dN} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)^{\scriptstyle{\mathsf{T}}}}_{dN \times \bullet} \underbrace{\Omega_j}_{\bullet \times \bullet} \underbrace{\left( \left. \frac{\partial \mathbf{e}_j(\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)} \right|_{\Delta \mathbf{x}^k = \mathbf{0}} \right)}_{\bullet \times dN} \underbrace{\frac{\partial (\mathbf{x}^k \boxplus \Delta \mathbf{x}^k)}{\partial \Delta \mathbf{x}^k}}_{dN \times cN}.\end{aligned}\end{split}\]</div> +<p>Using this notation, we obtain the optimal update as</p> +<div class="math notranslate nohighlight"> +\[\Delta \mathbf{x}^k = -H^{-1} \mathbf{b}. \label{eq:deltax}\]</div> +<p>We apply this update to the poses via <a class="reference internal" href="#equation-update">(3)</a> and repeat until convergence.</p> +<dl class="citation"> +<dt class="label" id="blanco2010tutorial"><span class="brackets"><a class="fn-backref" href="#id2">blanco2010tutorial</a></span></dt> +<dd><p>Blanco, J.-L.A tutorial onSE(3) transformation parameterization and on-manifold optimization.University of Malaga, Tech. Rep 3(2010)</p> +</dd> +<dt class="label" id="grisetti2010tutorial"><span class="brackets"><a class="fn-backref" href="#id3">grisetti2010tutorial</a></span></dt> +<dd><p>Grisetti, G., Kummerle, R., Stachniss, C., and Burgard, W.A tutorial on graph-based SLAM.IEEE Intelligent Transportation Systems Magazine 2, 4 (2010), 31–43.</p> +</dd> +</dl> +</section> +</section> +<section id="graph-slam-for-a-real-world-se-2-dataset"> +<h2>Graph SLAM for a real-world SE(2) dataset<a class="headerlink" href="#graph-slam-for-a-real-world-se-2-dataset" title="Permalink to this headline"></a></h2> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">graphslam.graph</span> <span class="kn">import</span> <span class="n">Graph</span> +<span class="kn">from</span> <span class="nn">graphslam.load</span> <span class="kn">import</span> <span class="n">load_g2o_se2</span> +</pre></div> +</div> +<section id="id4"> +<h3>Introduction<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h3> +<p>For a complete derivation of the Graph SLAM algorithm, please see +<a class="reference internal" href="#graph-slam-formulation">Graph SLAM Formulation</a>.</p> +<p>This notebook illustrates the iterative optimization of a real-world +<span class="math notranslate nohighlight">\(SE(2)\)</span> dataset. The code can be found in the <code class="docutils literal notranslate"><span class="pre">graphslam</span></code> +folder. For simplicity, numerical differentiation is used in lieu of +analytic Jacobians. This code originated from the +<a class="reference external" href="https://github.com/JeffLIrion/python-graphslam">python-graphslam</a> +repo, which is a full-featured Graph SLAM solver. The dataset in this +example is used with permission from Luca Carlone and was downloaded +from his <a class="reference external" href="https://lucacarlone.mit.edu/datasets/">website</a>.</p> +</section> +<section id="the-dataset"> +<h3>The Dataset<a class="headerlink" href="#the-dataset" title="Permalink to this headline"></a></h3> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="n">load_g2o_se2</span><span class="p">(</span><span class="s2">"data/input_INTEL.g2o"</span><span class="p">)</span> + +<span class="nb">print</span><span class="p">(</span><span class="s2">"Number of edges: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">_edges</span><span class="p">)))</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Number of vertices: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">_vertices</span><span class="p">)))</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Number</span> <span class="n">of</span> <span class="n">edges</span><span class="p">:</span> <span class="mi">1483</span> +<span class="n">Number</span> <span class="n">of</span> <span class="n">vertices</span><span class="p">:</span> <span class="mi">1228</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="sa">r</span><span class="s2">"Original ($\chi^2 = </span><span class="si">{:.0f}</span><span class="s2">$)"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">calc_chi2</span><span class="p">()))</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_SE2_example_4_0.png" src="../../../_images/graphSLAM_SE2_example_4_0.png" /> +<p>Each edge in this dataset is a constraint that compares the measured +<span class="math notranslate nohighlight">\(SE(2)\)</span> transformation between two poses to the expected +<span class="math notranslate nohighlight">\(SE(2)\)</span> transformation between them, as computed using the current +pose estimates. These edges can be classified into two categories:</p> +<ol class="arabic simple"> +<li><p>Odometry edges constrain two consecutive vertices, and the +measurement for the <span class="math notranslate nohighlight">\(SE(2)\)</span> transformation comes directly from +odometry data.</p></li> +<li><p>Scan-matching edges constrain two non-consecutive vertices. These +scan matches can be computed using, for example, 2-D LiDAR data or +landmarks; the details of how these constraints are determined is +beyond the scope of this example. This is often referred to as <em>loop +closure</em> in the Graph SLAM literature.</p></li> +</ol> +<p>We can easily parse out the two different types of edges present in this +dataset and plot them.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">parse_edges</span><span class="p">(</span><span class="n">g</span><span class="p">):</span> +<span class="w"> </span><span class="sd">"""Split the graph `g` into two graphs, one with only odometry edges and the other with only scan-matching edges.</span> + +<span class="sd"> Parameters</span> +<span class="sd"> ----------</span> +<span class="sd"> g : graphslam.graph.Graph</span> +<span class="sd"> The input graph</span> + +<span class="sd"> Returns</span> +<span class="sd"> -------</span> +<span class="sd"> g_odom : graphslam.graph.Graph</span> +<span class="sd"> A graph consisting of the vertices and odometry edges from `g`</span> +<span class="sd"> g_scan : graphslam.graph.Graph</span> +<span class="sd"> A graph consisting of the vertices and scan-matching edges from `g`</span> + +<span class="sd"> """</span> + <span class="n">edges_odom</span> <span class="o">=</span> <span class="p">[]</span> + <span class="n">edges_scan</span> <span class="o">=</span> <span class="p">[]</span> + + <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g</span><span class="o">.</span><span class="n">_edges</span><span class="p">:</span> + <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">vertex_ids</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">e</span><span class="o">.</span><span class="n">vertex_ids</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span> + <span class="n">edges_odom</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">edges_scan</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> + + <span class="n">g_odom</span> <span class="o">=</span> <span class="n">Graph</span><span class="p">(</span><span class="n">edges_odom</span><span class="p">,</span> <span class="n">g</span><span class="o">.</span><span class="n">_vertices</span><span class="p">)</span> + <span class="n">g_scan</span> <span class="o">=</span> <span class="n">Graph</span><span class="p">(</span><span class="n">edges_scan</span><span class="p">,</span> <span class="n">g</span><span class="o">.</span><span class="n">_vertices</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">g_odom</span><span class="p">,</span> <span class="n">g_scan</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g_odom</span><span class="p">,</span> <span class="n">g_scan</span> <span class="o">=</span> <span class="n">parse_edges</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> + +<span class="nb">print</span><span class="p">(</span><span class="s2">"Number of odometry edges: </span><span class="si">{:4d}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_odom</span><span class="o">.</span><span class="n">_edges</span><span class="p">)))</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"Number of scan-matching edges: </span><span class="si">{:4d}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_scan</span><span class="o">.</span><span class="n">_edges</span><span class="p">)))</span> + +<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">χ^2 error from odometry edges: </span><span class="si">{:11.3f}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g_odom</span><span class="o">.</span><span class="n">calc_chi2</span><span class="p">()))</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"χ^2 error from scan-matching edges: </span><span class="si">{:11.3f}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g_scan</span><span class="o">.</span><span class="n">calc_chi2</span><span class="p">()))</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Number</span> <span class="n">of</span> <span class="n">odometry</span> <span class="n">edges</span><span class="p">:</span> <span class="mi">1227</span> +<span class="n">Number</span> <span class="n">of</span> <span class="n">scan</span><span class="o">-</span><span class="n">matching</span> <span class="n">edges</span><span class="p">:</span> <span class="mi">256</span> + +<span class="n">χ</span><span class="o">^</span><span class="mi">2</span> <span class="n">error</span> <span class="kn">from</span> <span class="nn">odometry</span> <span class="n">edges</span><span class="p">:</span> <span class="mf">0.232</span> +<span class="n">χ</span><span class="o">^</span><span class="mi">2</span> <span class="n">error</span> <span class="kn">from</span> <span class="nn">scan</span><span class="o">-</span><span class="n">matching</span> <span class="n">edges</span><span class="p">:</span> <span class="mf">7191686.151</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g_odom</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Odometry edges"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_SE2_example_8_0.png" src="../../../_images/graphSLAM_SE2_example_8_0.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g_scan</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Scan-matching edges"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_SE2_example_9_0.png" src="../../../_images/graphSLAM_SE2_example_9_0.png" /> +</section> +<section id="optimization"> +<h3>Optimization<a class="headerlink" href="#optimization" title="Permalink to this headline"></a></h3> +<p>Initially, the pose estimates are consistent with the collected odometry +measurements, and the odometry edges contribute almost zero towards the +<span class="math notranslate nohighlight">\(\chi^2\)</span> error. However, there are large discrepancies between the +scan-matching constraints and the initial pose estimates. This is not +surprising, since small errors in odometry readings that are propagated +over time can lead to large errors in the robot’s trajectory. What makes +Graph SLAM effective is that it allows incorporation of multiple +different data sources into a single optimization problem.</p> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Iteration</span> <span class="n">chi</span><span class="o">^</span><span class="mi">2</span> <span class="n">rel</span><span class="o">.</span> <span class="n">change</span> +<span class="o">---------</span> <span class="o">-----</span> <span class="o">-----------</span> + <span class="mi">0</span> <span class="mf">7191686.3825</span> + <span class="mi">1</span> <span class="mf">320031728.8624</span> <span class="mf">43.500234</span> + <span class="mi">2</span> <span class="mf">125083004.3299</span> <span class="o">-</span><span class="mf">0.609154</span> + <span class="mi">3</span> <span class="mf">338155.9074</span> <span class="o">-</span><span class="mf">0.997297</span> + <span class="mi">4</span> <span class="mf">735.1344</span> <span class="o">-</span><span class="mf">0.997826</span> + <span class="mi">5</span> <span class="mf">215.8405</span> <span class="o">-</span><span class="mf">0.706393</span> + <span class="mi">6</span> <span class="mf">215.8405</span> <span class="o">-</span><span class="mf">0.000000</span> +</pre></div> +</div> +<figure class="align-default"> +<img alt="../../../_images/Graph_SLAM_optimization.gif" src="../../../_images/Graph_SLAM_optimization.gif" /> +</figure> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Optimized"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_SE2_example_13_0.png" src="../../../_images/graphSLAM_SE2_example_13_0.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">χ^2 error from odometry edges: </span><span class="si">{:7.3f}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g_odom</span><span class="o">.</span><span class="n">calc_chi2</span><span class="p">()))</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">"χ^2 error from scan-matching edges: </span><span class="si">{:7.3f}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g_scan</span><span class="o">.</span><span class="n">calc_chi2</span><span class="p">()))</span> +</pre></div> +</div> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">χ</span><span class="o">^</span><span class="mi">2</span> <span class="n">error</span> <span class="kn">from</span> <span class="nn">odometry</span> <span class="n">edges</span><span class="p">:</span> <span class="mf">142.189</span> +<span class="n">χ</span><span class="o">^</span><span class="mi">2</span> <span class="n">error</span> <span class="kn">from</span> <span class="nn">scan</span><span class="o">-</span><span class="n">matching</span> <span class="n">edges</span><span class="p">:</span> <span class="mf">73.652</span> +</pre></div> +</div> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g_odom</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Odometry edges"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_SE2_example_15_0.png" src="../../../_images/graphSLAM_SE2_example_15_0.png" /> +<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">g_scan</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Scan-matching edges"</span><span class="p">)</span> +</pre></div> +</div> +<img alt="../../../_images/graphSLAM_SE2_example_16_0.png" src="../../../_images/graphSLAM_SE2_example_16_0.png" /> +</section> +</section> +<section id="references"> +<h2>References:<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="http://www2.informatik.uni-freiburg.de/~stachnis/pdf/grisetti10titsmag.pdf">A Tutorial on Graph-Based SLAM</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../FastSLAM2/FastSLAM2.html" class="btn btn-neutral float-left" title="FastSLAM 2.0" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../path_planning/path_planning.html" class="btn btn-neutral float-right" title="Path Planning" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/slam/iterative_closest_point_matching/iterative_closest_point_matching.html b/modules/slam/iterative_closest_point_matching/iterative_closest_point_matching.html new file mode 100644 index 00000000000..b964247c12e --- /dev/null +++ b/modules/slam/iterative_closest_point_matching/iterative_closest_point_matching.html @@ -0,0 +1,162 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Iterative Closest Point (ICP) Matching — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="EKF SLAM" href="../ekf_slam/ekf_slam.html" /> + <link rel="prev" title="SLAM" href="../slam.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../slam.html">SLAM</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Iterative Closest Point (ICP) Matching</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#references">References</a></li> +</ul> +</li> +<li class="toctree-l2"><a class="reference internal" href="../ekf_slam/ekf_slam.html">EKF SLAM</a></li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM1/FastSLAM1.html">FastSLAM1.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="../FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="../graph_slam/graph_slam.html">Graph based SLAM</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../slam.html">SLAM</a> »</li> + <li>Iterative Closest Point (ICP) Matching</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/slam/iterative_closest_point_matching/iterative_closest_point_matching_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="iterative-closest-point-icp-matching"> +<span id="id1"></span><h1>Iterative Closest Point (ICP) Matching<a class="headerlink" href="#iterative-closest-point-icp-matching" title="Permalink to this headline"></a></h1> +<p>This is a 2D ICP matching example with singular value decomposition.</p> +<p>It can calculate a rotation matrix and a translation vector between +points to points.</p> +<img alt="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/iterative_closest_point/animation.gif" src="https://github.com/AtsushiSakai/PythonRoboticsGifs/raw/master/SLAM/iterative_closest_point/animation.gif" /> +<section id="references"> +<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://cs.gmu.edu/~kosecka/cs685/cs685-icp.pdf">Introduction to Mobile Robotics: Iterative Closest Point Algorithm</a></p></li> +</ul> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../slam.html" class="btn btn-neutral float-left" title="SLAM" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../ekf_slam/ekf_slam.html" class="btn btn-neutral float-right" title="EKF SLAM" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/slam/slam.html b/modules/slam/slam.html new file mode 100644 index 00000000000..e51e01beeee --- /dev/null +++ b/modules/slam/slam.html @@ -0,0 +1,189 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>SLAM — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Iterative Closest Point (ICP) Matching" href="iterative_closest_point_matching/iterative_closest_point_matching.html" /> + <link rel="prev" title="Normal vector estimation" href="../mapping/normal_vector_estimation/normal_vector_estimation.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">SLAM</a><ul> +<li class="toctree-l2"><a class="reference internal" href="iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html">EKF SLAM</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html">FastSLAM1.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a></li> +<li class="toctree-l2"><a class="reference internal" href="graph_slam/graph_slam.html">Graph based SLAM</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="../utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>SLAM</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/slam/slam_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="slam"> +<span id="id1"></span><h1>SLAM<a class="headerlink" href="#slam" title="Permalink to this headline"></a></h1> +<p>Simultaneous Localization and Mapping(SLAM) examples</p> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="iterative_closest_point_matching/iterative_closest_point_matching.html">Iterative Closest Point (ICP) Matching</a><ul> +<li class="toctree-l2"><a class="reference internal" href="iterative_closest_point_matching/iterative_closest_point_matching.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="ekf_slam/ekf_slam.html">EKF SLAM</a><ul> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#simulation">Simulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#introduction">Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#algorithm-walk-through">Algorithm Walk through</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#predict">1- Predict</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#update">2 - Update</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#observation-step">Observation Step</a></li> +<li class="toctree-l2"><a class="reference internal" href="ekf_slam/ekf_slam.html#references">References:</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="FastSLAM1/FastSLAM1.html">FastSLAM1.0</a><ul> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#simulation">Simulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#introduction">Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#algorithm-walk-through">Algorithm walk through</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#predict">1- Predict</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#update">2- Update</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#resampling">3- Resampling</a></li> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM1/FastSLAM1.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="FastSLAM2/FastSLAM2.html">FastSLAM 2.0</a><ul> +<li class="toctree-l2"><a class="reference internal" href="FastSLAM2/FastSLAM2.html#references">References</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="graph_slam/graph_slam.html">Graph based SLAM</a><ul> +<li class="toctree-l2"><a class="reference internal" href="graph_slam/graph_slam.html#graph-slam">Graph SLAM</a></li> +<li class="toctree-l2"><a class="reference internal" href="graph_slam/graph_slam.html#graph-slam-formulation">Graph SLAM Formulation</a></li> +<li class="toctree-l2"><a class="reference internal" href="graph_slam/graph_slam.html#graph-slam-for-a-real-world-se-2-dataset">Graph SLAM for a real-world SE(2) dataset</a></li> +<li class="toctree-l2"><a class="reference internal" href="graph_slam/graph_slam.html#references">References:</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../mapping/normal_vector_estimation/normal_vector_estimation.html" class="btn btn-neutral float-left" title="Normal vector estimation" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="iterative_closest_point_matching/iterative_closest_point_matching.html" class="btn btn-neutral float-right" title="Iterative Closest Point (ICP) Matching" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/utils/plot/plot.html b/modules/utils/plot/plot.html new file mode 100644 index 00000000000..28391f6176a --- /dev/null +++ b/modules/utils/plot/plot.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Plotting Utilities — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> + <script src="../../../_static/jquery.js"></script> + <script src="../../../_static/underscore.js"></script> + <script src="../../../_static/doctools.js"></script> + <script src="../../../_static/clipboard.min.js"></script> + <script src="../../../_static/copybutton.js"></script> + <script src="../../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../../genindex.html" /> + <link rel="search" title="Search" href="../../../search.html" /> + <link rel="next" title="Appendix" href="../../appendix/appendix.html" /> + <link rel="prev" title="Utilities" href="../utils.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../control/control.html">Control</a></li> +<li class="toctree-l1 current"><a class="reference internal" href="../utils.html">Utilities</a><ul class="current"> +<li class="toctree-l2 current"><a class="current reference internal" href="#">Plotting Utilities</a><ul> +<li class="toctree-l3"><a class="reference internal" href="#plot-curvature">plot_curvature</a></li> +</ul> +</li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../../index.html" class="icon icon-home"></a> »</li> + <li><a href="../utils.html">Utilities</a> »</li> + <li>Plotting Utilities</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/utils/plot/plot_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="plotting-utilities"> +<span id="plot-utils"></span><h1>Plotting Utilities<a class="headerlink" href="#plotting-utilities" title="Permalink to this headline"></a></h1> +<p>This module contains a number of utility functions for plotting data.</p> +<section id="plot-curvature"> +<span id="id1"></span><h2>plot_curvature<a class="headerlink" href="#plot-curvature" title="Permalink to this headline"></a></h2> +<dl class="py function"> +<dt class="sig sig-object py" id="utils.plot.plot_curvature"> +<span class="sig-prename descclassname"><span class="pre">utils.plot.</span></span><span class="sig-name descname"><span class="pre">plot_curvature</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">x_list</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">y_list</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">heading_list</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">curvature</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">k</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0.01</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">c</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">'-c'</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">label</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">'Curvature'</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="../../../_modules/utils/plot.html#plot_curvature"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#utils.plot.plot_curvature" title="Permalink to this definition"></a></dt> +<dd><p>Plot curvature on 2D path. This plot is a line from the original path, +the lateral distance from the original path shows curvature magnitude. +Left turning shows right side plot, right turning shows left side plot. +For straight path, the curvature plot will be on the path, because +curvature is 0 on the straight path.</p> +<dl class="field-list simple"> +<dt class="field-odd">Parameters</dt> +<dd class="field-odd"><ul class="simple"> +<li><p><strong>x_list</strong> (<em>array_like</em>) – x position list of the path</p></li> +<li><p><strong>y_list</strong> (<em>array_like</em>) – y position list of the path</p></li> +<li><p><strong>heading_list</strong> (<em>array_like</em>) – heading list of the path</p></li> +<li><p><strong>curvature</strong> (<em>array_like</em>) – curvature list of the path</p></li> +<li><p><strong>k</strong> (<em>float</em>) – curvature scale factor to calculate distance from the original path</p></li> +<li><p><strong>c</strong> (<em>string</em>) – color of the plot</p></li> +<li><p><strong>label</strong> (<em>string</em>) – label of the plot</p></li> +</ul> +</dd> +</dl> +</dd></dl> + +<img alt="../../../_images/curvature_plot.png" src="../../../_images/curvature_plot.png" /> +</section> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../utils.html" class="btn btn-neutral float-left" title="Utilities" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="../../appendix/appendix.html" class="btn btn-neutral float-right" title="Appendix" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/modules/utils/utils.html b/modules/utils/utils.html new file mode 100644 index 00000000000..8643bc14bbb --- /dev/null +++ b/modules/utils/utils.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Utilities — PythonRobotics documentation</title> + <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="../../_static/dark_mode_css/dark.css" type="text/css" /> + <!--[if lt IE 9]> + <script src="../../_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script> + <script src="../../_static/jquery.js"></script> + <script src="../../_static/underscore.js"></script> + <script src="../../_static/doctools.js"></script> + <script src="../../_static/clipboard.min.js"></script> + <script src="../../_static/copybutton.js"></script> + <script src="../../_static/dark_mode_js/default_dark.js"></script> + <script src="../../_static/dark_mode_js/theme_switcher.js"></script> + <script src="../../_static/js/theme.js"></script> + <link rel="index" title="Index" href="../../genindex.html" /> + <link rel="search" title="Search" href="../../search.html" /> + <link rel="next" title="Plotting Utilities" href="plot/plot.html" /> + <link rel="prev" title="Move to a Pose Control" href="../control/move_to_a_pose_control/move_to_a_pose_control.html" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="../../index.html" class="icon icon-home"> PythonRobotics + <img src="../../_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul class="current"> +<li class="toctree-l1"><a class="reference internal" href="../../getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="../introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="../localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="../mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="../slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="../path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="../arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="../bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="../control/control.html">Control</a></li> +<li class="toctree-l1 current"><a class="current reference internal" href="#">Utilities</a><ul> +<li class="toctree-l2"><a class="reference internal" href="plot/plot.html">Plotting Utilities</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="../appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="../../how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="../../index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="../../index.html" class="icon icon-home"></a> »</li> + <li>Utilities</li> + <li class="wy-breadcrumbs-aside"> + <a href="https://github.com/AtsushiSakai/PythonRobotics/blob/master/docs/modules/utils/utils_main.rst" class="fa fa-github"> Edit on GitHub</a> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <section id="utilities"> +<span id="utils"></span><h1>Utilities<a class="headerlink" href="#utilities" title="Permalink to this headline"></a></h1> +<p>Common utilities for PythonRobotics.</p> +<div class="toctree-wrapper compound"> +<p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="plot/plot.html">Plotting Utilities</a><ul> +<li class="toctree-l2"><a class="reference internal" href="plot/plot.html#plot-curvature">plot_curvature</a></li> +</ul> +</li> +</ul> +</div> +</section> + + + </div> + </div> + <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> + <a href="../control/move_to_a_pose_control/move_to_a_pose_control.html" class="btn btn-neutral float-left" title="Move to a Pose Control" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> + <a href="plot/plot.html" class="btn btn-neutral float-right" title="Plotting Utilities" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> + </div> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + +</body> +</html> \ No newline at end of file diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 1215375ed9b..00000000000 --- a/mypy.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mypy] -ignore_missing_imports = True \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000000..aa6e436ffc6 Binary files /dev/null and b/objects.inv differ diff --git a/requirements/environment.yml b/requirements/environment.yml deleted file mode 100644 index afbb3fb8cec..00000000000 --- a/requirements/environment.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: python_robotics -channels: - - conda-forge -dependencies: - - python=3.12 - - pip - - scipy - - numpy - - cvxpy - - matplotlib diff --git a/requirements/requirements.txt b/requirements/requirements.txt deleted file mode 100644 index 5438678f87d..00000000000 --- a/requirements/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -numpy == 2.2.4 -scipy == 1.15.2 -matplotlib == 3.10.1 -cvxpy == 1.5.3 -pytest == 8.3.5 # For unit test -pytest-xdist == 3.6.1 # For unit test -mypy == 1.15.0 # For unit test -ruff == 0.11.0 # For unit test diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 5823ca3db75..00000000000 --- a/ruff.toml +++ /dev/null @@ -1,18 +0,0 @@ -line-length = 88 - -select = ["F", "E", "W", "UP"] -ignore = ["E501", "E741", "E402"] -exclude = [ -] - -# Assume Python 3.11 -target-version = "py312" - -[per-file-ignores] - -[mccabe] -# Unlike Flake8, default to a complexity level of 10. -max-complexity = 10 - -[pydocstyle] -convention = "numpy" diff --git a/runtests.sh b/runtests.sh deleted file mode 100755 index 12d1b804534..00000000000 --- a/runtests.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -echo "Run test suites! " - -# === pytest based test runner === -# -Werror: warning as error -# --durations=0: show ranking of test durations -# -l (--showlocals); show local variables when test failed -pytest tests -l -Werror --durations=0 diff --git a/search.html b/search.html new file mode 100644 index 00000000000..0bfaa109372 --- /dev/null +++ b/search.html @@ -0,0 +1,152 @@ +<!DOCTYPE html> +<html class="writer-html5" lang="en" > +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Search — PythonRobotics documentation</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/css/theme.css" type="text/css" /> + <link rel="stylesheet" href="_static/plot_directive.css" type="text/css" /> + <link rel="stylesheet" href="_static/copybutton.css" type="text/css" /> + <link rel="stylesheet" href="_static/custom.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/general.css" type="text/css" /> + <link rel="stylesheet" href="_static/dark_mode_css/dark.css" type="text/css" /> + + <!--[if lt IE 9]> + <script src="_static/js/html5shiv.min.js"></script> + <![endif]--> + + <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + <script src="_static/clipboard.min.js"></script> + <script src="_static/copybutton.js"></script> + <script src="_static/dark_mode_js/default_dark.js"></script> + <script src="_static/dark_mode_js/theme_switcher.js"></script> + <script src="_static/js/theme.js"></script> + <script src="_static/searchtools.js"></script> + <script src="_static/language_data.js"></script> + <link rel="index" title="Index" href="genindex.html" /> + <link rel="search" title="Search" href="#" /> +</head> + +<body class="wy-body-for-nav"> + <div class="wy-grid-for-nav"> + <nav data-toggle="wy-nav-shift" class="wy-nav-side"> + <div class="wy-side-scroll"> + <div class="wy-side-nav-search" > + + <a href="index.html" class="icon icon-home"> PythonRobotics + <img src="_static/icon.png" class="logo" alt="Logo"/> + </a> +<div role="search"> + <form id="rtd-search-form" class="wy-form" action="#" method="get"> + <input type="text" name="q" placeholder="Search docs" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9612347954373886" + crossorigin="anonymous"></script> +<!-- PythonRoboticsDoc --> +<ins class="adsbygoogle" + style="display:block" + data-ad-client="ca-pub-9612347954373886" + data-ad-slot="1579532132" + data-ad-format="auto" + data-full-width-responsive="true"></ins> +<script> + (adsbygoogle = window.adsbygoogle || []).push({}); +</script> + + </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> + <p class="caption" role="heading"><span class="caption-text">Contents</span></p> +<ul> +<li class="toctree-l1"><a class="reference internal" href="getting_started.html">Getting Started</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/introduction.html">Introduction</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/localization/localization.html">Localization</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/mapping/mapping.html">Mapping</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/slam/slam.html">SLAM</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_planning/path_planning.html">Path Planning</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/path_tracking/path_tracking.html">Path Tracking</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/arm_navigation/arm_navigation.html">Arm Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/aerial_navigation/aerial_navigation.html">Aerial Navigation</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/bipedal/bipedal.html">Bipedal</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/control/control.html">Control</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/utils/utils.html">Utilities</a></li> +<li class="toctree-l1"><a class="reference internal" href="modules/appendix/appendix.html">Appendix</a></li> +<li class="toctree-l1"><a class="reference internal" href="how_to_contribute.html">How To Contribute</a></li> +</ul> + + </div> + </div> + </nav> + + <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > + <i data-toggle="wy-nav-top" class="fa fa-bars"></i> + <a href="index.html">PythonRobotics</a> + </nav> + + <div class="wy-nav-content"> + <div class="rst-content"> + <div role="navigation" aria-label="Page navigation"> + <ul class="wy-breadcrumbs"> + <li><a href="index.html" class="icon icon-home"></a> »</li> + <li>Search</li> + <li class="wy-breadcrumbs-aside"> + </li> + </ul> + <hr/> +</div> + <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> + <div itemprop="articleBody"> + + <noscript> + <div id="fallback" class="admonition warning"> + <p class="last"> + Please activate JavaScript to enable the search functionality. + </p> + </div> + </noscript> + + + <div id="search-results"> + + </div> + + </div> + </div> + <footer> + + <hr/> + + <div role="contentinfo"> + <p>© Copyright 2018-2021, Atsushi Sakai.</p> + </div> + + Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a + <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> + provided by <a href="https://readthedocs.org">Read the Docs</a>. + + +</footer> + </div> + </div> + </section> + </div> + <script> + jQuery(function () { + SphinxRtdTheme.Navigation.enable(true); + }); + </script> + <script> + jQuery(function() { Search.loadIndex("searchindex.js"); }); + </script> + + <script id="searchindexloader"></script> + + + +</body> +</html> \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000000..e065f4a191d --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["getting_started","how_to_contribute","index","modules/aerial_navigation/aerial_navigation","modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following","modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing","modules/appendix/Kalmanfilter_basics","modules/appendix/Kalmanfilter_basics_2","modules/appendix/appendix","modules/arm_navigation/arm_navigation","modules/arm_navigation/n_joint_arm_to_point_control","modules/arm_navigation/obstacle_avoidance_arm_navigation","modules/arm_navigation/planar_two_link_ik","modules/bipedal/bipedal","modules/bipedal/bipedal_planner/bipedal_planner","modules/control/control","modules/control/inverted_pendulum_control/inverted_pendulum_control","modules/control/move_to_a_pose_control/move_to_a_pose_control","modules/introduction","modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization","modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization","modules/localization/histogram_filter_localization/histogram_filter_localization","modules/localization/localization","modules/localization/particle_filter_localization/particle_filter_localization","modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization","modules/mapping/circle_fitting/circle_fitting","modules/mapping/gaussian_grid_map/gaussian_grid_map","modules/mapping/k_means_object_clustering/k_means_object_clustering","modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial","modules/mapping/mapping","modules/mapping/ndt_map/ndt_map","modules/mapping/normal_vector_estimation/normal_vector_estimation","modules/mapping/point_cloud_sampling/point_cloud_sampling","modules/mapping/ray_casting_grid_map/ray_casting_grid_map","modules/mapping/rectangle_fitting/rectangle_fitting","modules/path_planning/bezier_path/bezier_path","modules/path_planning/bspline_path/bspline_path","modules/path_planning/bugplanner/bugplanner","modules/path_planning/clothoid_path/clothoid_path","modules/path_planning/coverage_path/coverage_path","modules/path_planning/cubic_spline/cubic_spline","modules/path_planning/dubins_path/dubins_path","modules/path_planning/dynamic_window_approach/dynamic_window_approach","modules/path_planning/eta3_spline/eta3_spline","modules/path_planning/frenet_frame_path/frenet_frame_path","modules/path_planning/grid_base_search/grid_base_search","modules/path_planning/hybridastar/hybridastar","modules/path_planning/lqr_path/lqr_path","modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator","modules/path_planning/path_planning","modules/path_planning/prm_planner/prm_planner","modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner","modules/path_planning/reeds_shepp_path/reeds_shepp_path","modules/path_planning/rrt/rrt","modules/path_planning/state_lattice_planner/state_lattice_planner","modules/path_planning/visibility_road_map_planner/visibility_road_map_planner","modules/path_planning/vrm_planner/vrm_planner","modules/path_tracking/cgmres_nmpc/cgmres_nmpc","modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control","modules/path_tracking/lqr_steering_control/lqr_steering_control","modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control","modules/path_tracking/path_tracking","modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking","modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control","modules/path_tracking/stanley_control/stanley_control","modules/slam/FastSLAM1/FastSLAM1","modules/slam/FastSLAM2/FastSLAM2","modules/slam/ekf_slam/ekf_slam","modules/slam/graph_slam/graph_slam","modules/slam/iterative_closest_point_matching/iterative_closest_point_matching","modules/slam/slam","modules/utils/plot/plot","modules/utils/utils"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["getting_started_main.rst","how_to_contribute_main.rst","index_main.rst","modules/aerial_navigation/aerial_navigation_main.rst","modules/aerial_navigation/drone_3d_trajectory_following/drone_3d_trajectory_following_main.rst","modules/aerial_navigation/rocket_powered_landing/rocket_powered_landing_main.rst","modules/appendix/Kalmanfilter_basics_main.rst","modules/appendix/Kalmanfilter_basics_2_main.rst","modules/appendix/appendix_main.rst","modules/arm_navigation/arm_navigation_main.rst","modules/arm_navigation/n_joint_arm_to_point_control_main.rst","modules/arm_navigation/obstacle_avoidance_arm_navigation_main.rst","modules/arm_navigation/planar_two_link_ik_main.rst","modules/bipedal/bipedal_main.rst","modules/bipedal/bipedal_planner/bipedal_planner_main.rst","modules/control/control_main.rst","modules/control/inverted_pendulum_control/inverted_pendulum_control_main.rst","modules/control/move_to_a_pose_control/move_to_a_pose_control_main.rst","modules/introduction_main.rst","modules/localization/ensamble_kalman_filter_localization_files/ensamble_kalman_filter_localization_main.rst","modules/localization/extended_kalman_filter_localization_files/extended_kalman_filter_localization_main.rst","modules/localization/histogram_filter_localization/histogram_filter_localization_main.rst","modules/localization/localization_main.rst","modules/localization/particle_filter_localization/particle_filter_localization_main.rst","modules/localization/unscented_kalman_filter_localization/unscented_kalman_filter_localization_main.rst","modules/mapping/circle_fitting/circle_fitting_main.rst","modules/mapping/gaussian_grid_map/gaussian_grid_map_main.rst","modules/mapping/k_means_object_clustering/k_means_object_clustering_main.rst","modules/mapping/lidar_to_grid_map_tutorial/lidar_to_grid_map_tutorial_main.rst","modules/mapping/mapping_main.rst","modules/mapping/ndt_map/ndt_map_main.rst","modules/mapping/normal_vector_estimation/normal_vector_estimation_main.rst","modules/mapping/point_cloud_sampling/point_cloud_sampling_main.rst","modules/mapping/ray_casting_grid_map/ray_casting_grid_map_main.rst","modules/mapping/rectangle_fitting/rectangle_fitting_main.rst","modules/path_planning/bezier_path/bezier_path_main.rst","modules/path_planning/bspline_path/bspline_path_main.rst","modules/path_planning/bugplanner/bugplanner_main.rst","modules/path_planning/clothoid_path/clothoid_path_main.rst","modules/path_planning/coverage_path/coverage_path_main.rst","modules/path_planning/cubic_spline/cubic_spline_main.rst","modules/path_planning/dubins_path/dubins_path_main.rst","modules/path_planning/dynamic_window_approach/dynamic_window_approach_main.rst","modules/path_planning/eta3_spline/eta3_spline_main.rst","modules/path_planning/frenet_frame_path/frenet_frame_path_main.rst","modules/path_planning/grid_base_search/grid_base_search_main.rst","modules/path_planning/hybridastar/hybridastar_main.rst","modules/path_planning/lqr_path/lqr_path_main.rst","modules/path_planning/model_predictive_trajectory_generator/model_predictive_trajectory_generator_main.rst","modules/path_planning/path_planning_main.rst","modules/path_planning/prm_planner/prm_planner_main.rst","modules/path_planning/quintic_polynomials_planner/quintic_polynomials_planner_main.rst","modules/path_planning/reeds_shepp_path/reeds_shepp_path_main.rst","modules/path_planning/rrt/rrt_main.rst","modules/path_planning/state_lattice_planner/state_lattice_planner_main.rst","modules/path_planning/visibility_road_map_planner/visibility_road_map_planner_main.rst","modules/path_planning/vrm_planner/vrm_planner_main.rst","modules/path_tracking/cgmres_nmpc/cgmres_nmpc_main.rst","modules/path_tracking/lqr_speed_and_steering_control/lqr_speed_and_steering_control_main.rst","modules/path_tracking/lqr_steering_control/lqr_steering_control_main.rst","modules/path_tracking/model_predictive_speed_and_steering_control/model_predictive_speed_and_steering_control_main.rst","modules/path_tracking/path_tracking_main.rst","modules/path_tracking/pure_pursuit_tracking/pure_pursuit_tracking_main.rst","modules/path_tracking/rear_wheel_feedback_control/rear_wheel_feedback_control_main.rst","modules/path_tracking/stanley_control/stanley_control_main.rst","modules/slam/FastSLAM1/FastSLAM1_main.rst","modules/slam/FastSLAM2/FastSLAM2_main.rst","modules/slam/ekf_slam/ekf_slam_main.rst","modules/slam/graph_slam/graph_slam_main.rst","modules/slam/iterative_closest_point_matching/iterative_closest_point_matching_main.rst","modules/slam/slam_main.rst","modules/utils/plot/plot_main.rst","modules/utils/utils_main.rst"],objects:{"Mapping.ndt_map.ndt_map":[[30,0,1,"","NDTMap"]],"Mapping.ndt_map.ndt_map.NDTMap":[[30,0,1,"","NDTGrid"],[30,1,1,"","grid_index_map"],[30,1,1,"","min_n_points"],[30,1,1,"","resolution"]],"Mapping.ndt_map.ndt_map.NDTMap.NDTGrid":[[30,1,1,"","center_grid_x"],[30,1,1,"","center_grid_y"],[30,1,1,"","covariance"],[30,1,1,"","eig_values"],[30,1,1,"","eig_vec"],[30,1,1,"","mean_x"],[30,1,1,"","mean_y"],[30,1,1,"","n_points"]],"Mapping.normal_vector_estimation.normal_vector_estimation":[[31,2,1,"","calc_normal_vector"],[31,2,1,"","ransac_normal_vector_estimation"]],"Mapping.point_cloud_sampling.point_cloud_sampling":[[32,2,1,"","farthest_point_sampling"],[32,2,1,"","poisson_disk_sampling"],[32,2,1,"","voxel_point_sampling"]],"Mapping.rectangle_fitting.rectangle_fitting":[[34,0,1,"","LShapeFitting"]],"Mapping.rectangle_fitting.rectangle_fitting.LShapeFitting":[[34,0,1,"","Criteria"],[34,1,1,"","R0"],[34,1,1,"","Rd"],[34,1,1,"","criteria"],[34,1,1,"","d_theta_deg_for_search"],[34,3,1,"","fitting"],[34,1,1,"","min_dist_of_closeness_criteria"]],"PathPlanning.BSplinePath.bspline_path":[[36,2,1,"","approximate_b_spline_path"],[36,2,1,"","interpolate_b_spline_path"]],"PathPlanning.CubicSpline.cubic_spline_planner":[[40,0,1,"","CubicSpline1D"],[40,0,1,"","CubicSpline2D"]],"PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline1D":[[40,3,1,"","calc_first_derivative"],[40,3,1,"","calc_position"],[40,3,1,"","calc_second_derivative"]],"PathPlanning.CubicSpline.cubic_spline_planner.CubicSpline2D":[[40,3,1,"","calc_curvature"],[40,3,1,"","calc_position"],[40,3,1,"","calc_yaw"]],"PathPlanning.DubinsPath.dubins_path_planner":[[41,2,1,"","plan_dubins_path"]],"utils.plot":[[71,2,1,"","plot_curvature"]]},objnames:{"0":["py","class","Python class"],"1":["py","attribute","Python attribute"],"2":["py","function","Python function"],"3":["py","method","Python method"]},objtypes:{"0":"py:class","1":"py:attribute","2":"py:function","3":"py:method"},terms:{"0":[2,5,6,7,12,16,20,21,28,31,36,38,40,41,51,57,60,67,68,70,71],"000000":68,"0004460978857535104":68,"001":67,"0068996":6,"00766623":6,"01":[5,65,68,71],"010":68,"010729072751057656":68,"0126109674819155":68,"02":[28,68],"0224618077401504":6,"023098460073039763":65,"05":12,"05064471":6,"06219243":6,"06326":53,"07":65,"084":68,"08855629":6,"08868895":6,"0f":68,"0x139196438":6,"1":[5,6,7,12,16,17,20,21,23,28,30,31,36,38,41,51,57,60,66,68,70],"10":[6,10,28,65,67,68],"100":[6,12,28,65,68],"1000":[6,32,36],"10703":[0,2],"11":[0,5,6,68],"11555291":6,"12":[6,68],"122":28,"1227":68,"1228":68,"125083004":68,"12561859":6,"12a_4t":51,"12t":51,"13":6,"130":6,"1344":68,"13957621":6,"14":[5,6],"14142933":6,"142":68,"1483":68,"15":[6,12,41,52,65,67,68],"150":28,"151":68,"1571437":6,"16":6,"1601":53,"17":6,"18":[6,68],"180":6,"1808":[0,2],"189":68,"19":6,"1972439134893":68,"1985":28,"1d":[49,68],"1e":5,"1n":6,"2":[2,5,6,8,12,16,17,21,23,28,30,36,38,41,51,52,57,60,70],"20":[6,7,28,65,67,68],"2010":68,"20a_5t":51,"20t":51,"21":6,"215":68,"21534324":6,"22":6,"23":6,"230":6,"232":68,"24":6,"25":[6,12,65,68],"256":68,"27":6,"2_":7,"2a":38,"2a_2":51,"2a_2t":51,"2c":40,"2c_":40,"2cx":40,"2d":[6,17,20,21,26,27,28,30,33,37,38,39,41,42,45,49,51,68,69,71],"2l":16,"2l_0l_1":12,"2lmsin":16,"2n":6,"2x1":67,"2x2":[30,65,67],"2z":6,"3":[0,2,5,6,7,12,17,21,28,31,36,41,49,51,52,67,68,70],"30":[6,28,67,68],"30943011":6,"31":68,"320031728":68,"3299":68,"338155":68,"34638597":6,"35":12,"3825":68,"38334183":6,"3a_3t":51,"3d":[2,3,6,29],"3dof":68,"3dx":40,"3f":68,"3t":51,"3x1":67,"4":[5,6,7,12,20,21,28,35,36,51,68],"40":28,"400":7,"4000000000000001":6,"414":68,"42029769":6,"427649841628278":68,"428":68,"43":68,"448":68,"45":[12,41,68],"45725355":6,"49420941":6,"499":65,"4a_4t":51,"4d":68,"4n":40,"4t":51,"5":[5,6,7,12,28,36,51,65,67,68],"50":[28,65,67,68],"500234":68,"512":68,"524048014922737":68,"53116527":6,"56812114":6,"5a_5t":51,"5a_st":51,"5t":51,"6":[5,6,7,12,28,40,41,51,60,68],"60":6,"600":5,"605077":6,"609154":68,"64203286":6,"65":5,"652":68,"67898872":6,"6a_3t":51,"6dx":40,"6t":51,"7":[5,6,7,12,31,40,51,65,68],"706393":68,"716":68,"7191686":68,"73":68,"735":68,"75":12,"750000000000007":68,"76":6,"785":68,"8":[6,7,12,28,41,51,65,68],"80":[6,7],"82":65,"8405":68,"8624":68,"9":[1,6,7,12,51,68],"90":7,"9074":68,"95":5,"951154575772496e":65,"976":68,"985":68,"99":[5,7,31],"997297":68,"997826":68,"\u03b4":60,"\u03c6":60,"\u03c7":68,"\u975e\u7dda\u5f62\u30e2\u30c7\u30eb\u4e88\u6e2c\u5236\u5fa1\u306b\u304a\u3051\u308bcgmres\u6cd5\u3092python\u3067\u5b9f\u88c5\u3059\u308b":57,"a\u00e7\u0131kme\u015f":5,"beh\u00e7et":5,"case":[1,6,7,21,30,36,65,67,68],"class":[12,15,30,34,40,65],"default":[31,32,36,41],"do":[7,12,65],"final":[5,7,17,21,38,41,50,55,56],"float":[17,28,31,32,40,41,71],"function":[1,6,7,12,16,20,28,30,32,34,36,45,49,57,60,67,68,71],"import":[5,6,7,12,28,36,40,65,67,68],"int":[7,28,32,36,65,67],"n\u03c7":68,"new":[2,6,7,30,65,67],"return":[5,6,7,12,17,28,31,32,34,36,40,41,65,67,68],"short":1,"true":[5,6,7,20,21,23,25,28,40,41,65,67,68],"try":[1,12,65],"var":6,"while":[28,65,67],A:[1,5,6,7,12,16,17,28,31,35,38,40,41,46,47,49,52,53,60,62,63,67,68],And:[20,51],As:[40,65,67,68],At:[1,65,67,68],But:[6,17,21,28],By:68,For:[0,6,7,21,28,40,41,51,65,67,68,71],If:[1,7,12,16,21,31,34,35,36,41,51,55,65,67],In:[0,1,6,7,10,12,17,20,21,28,30,31,32,34,38,45,50,51,53,55,56,65,67,68],It:[0,1,6,7,12,21,23,34,35,36,40,41,51,65,68,69],Its:[20,45],No:68,Not:[36,68],OF:65,Of:[2,67],On:[7,39,41],One:1,That:[6,68],The:[0,1,2,6,7,12,16,17,20,21,23,24,25,28,30,32,34,36,38,40,42,44,45,50,53,55,56,60,62,64,65,66,67],Then:[12,30,51,68],There:[21,31],These:[6,40,67,68],To:[2,6,17,28,65,67,68],With:67,_0:40,_1:68,_2:68,_:[6,7,12,17,20,40,41,65,68],__init__:[12,65],_array_lik:32,_dom_class:65,_edg:68,_i:[36,68],_j:[40,68],_last_:6,_m:68,_n:68,_probabilist:[21,23],_scalartype_co:32,_t:20,_type:32,_vertic:68,a_0:51,a_1:51,a_1t:51,a_2:51,a_2t:51,a_3:51,a_3t:51,a_4:51,a_4t:51,a_5:51,a_5t:51,a_:[40,51],a_st:51,ab:[0,65,68],abid:6,abil:28,abl:[7,68],about:[6,17,67,68],abov:[6,7,31,40,65],ac_j:40,academia:0,accel:60,acceler:[7,51],accept:1,access:1,accord:[6,65,68],account:[7,12,17,67],accumul:67,accur:[36,38],aco:41,acquir:32,across:6,act:67,actual:[12,65,67],actuat:17,ad:[2,6,7,12,21,36,67,68],adapt:29,add:[0,65,67],add_new_lm:65,addit:[6,7,36,68],adjac:[16,55],adjust:[6,36,65],admiss:53,advantag:34,aerial:2,after:[1,7,21,40,65,67,68],again:[7,51,65,68],agre:1,agv:51,albeit:68,algebra:16,algorithm:[0,2,6,8,15,22,27,28,30,32,34,37,38,39,41,48,49,53,58,69,70],algotihm:28,align:[6,7,17,38,68],all:[1,6,7,21,31,32,34,36,41,51,67,68],allow:[6,7,12,34,68],almost:68,along:[7,17,51,67],alpha:[12,17,28,41,68],alpha_m:5,alreadi:12,also:[1,6,7,12,20,36,40,65,67,68],although:32,alwai:6,among:[41,68],an:[0,6,7,12,16,17,25,28,31,32,34,39,45,53,59,60,65,67,68],analyt:[40,41,68],anatom:12,anchor:68,andrew:67,ang:28,angl:[6,12,16,17,28,34,40,41,60,65,67,68],angle1:68,angle2:68,anglen:[65,67],angular:[5,17,65,67],ani:[1,7,32,36],anim:[0,45,50,55,56,66],annot:12,antialias:6,anywher:68,api:[29,49],apollo:59,apolloauto:59,appear:67,append:[28,40,65,67,68],appendix:2,appendleft:28,appli:[16,34,67,68],applic:[1,2,17,53,67,68],appreci:1,approach:[2,28,49,65,68],appropri:67,approx:[16,68],approxim:[40,49],approximate_b_spline_path:36,ar:[0,1,2,6,7,17,20,21,23,24,25,28,31,32,34,36,40,41,44,45,50,51,53,55,56,57,65,67,68],arang:[6,28,40],arc:55,arctan2:17,area:[10,12,28,55],arg:68,argmin:68,arithmet:6,arm:2,around:[6,60],arrai:[5,6,7,12,28,31,36,40,41,65,67,68],array_lik:[36,71],arriv:68,arrow_length:41,arrowprop:12,artifact:1,artifici:23,arxiv:0,ascend:40,assign:7,associ:[6,65,67,68],assum:[21,23,40,51,55,68],ast:7,atan2:[12,41,65,67],atsushi:67,atsushi_twi:67,atsushisakai:[0,1,20,60],attach:16,attempt:12,au:12,author:[67,68],autom:28,automat:[53,64],automobil:64,autonom:[0,35,53,58,59,64],avail:[67,68],averag:[6,21,32,41,65],avoid:[2,9,42,45,68],awai:67,ax1:65,ax2:65,ax3:65,ax:[6,16,51],axes3d:6,axi:[6,12,17,28,34,40,41,51,65,67],az_k:60,az_t:60,b:[2,5,6,7,12,16,20,38,40,49,51,60,65,67,68],b_0:51,b_1t:51,b_2t:51,b_3t:51,b_4t:51,b_5t:51,b_:[36,40],b_orig:36,back:12,backer:1,background:1,backward:52,bailei:66,balanc:16,bar:[6,7,60,67],base:[2,7,12,16,17,21,28,30,31,32,34,35,40,41,46,49,51,53,60,65,66,67,70],basi:36,basic:[0,2,8,28,49],batch:49,bay:[6,8,21,68],bayes_filt:7,bayesian:[7,21],beacon:67,beam:28,bear:[67,68],becaus:[6,7,12,17,32,71],becom:[1,6,7,32,67],been:[7,67,68],befor:[1,7,12,65,67,68],begin:[5,6,7,16,20,36,38,40,51,57,60,65,67,68],beginn:0,behavior:0,behind:[0,68],beizer:35,bel:7,belief:[7,65,67,68],believ:67,bell:6,belong:65,below:[7,17,34,40,55],berkelei:60,best:[12,34],beta:[12,17,41],better:68,between:[6,7,12,17,28,31,32,34,38,40,41,55,65,67,68,69],beyond:68,bezier:[2,49],bf:[7,57],bia:6,bias:49,bibtex:2,bidirect:49,big:6,bigger:36,binari:68,biped:2,bit:53,bivari:6,black:[12,20,21,23,30,44,53,55,65,67,68],blanco2010tutori:68,blanco:68,blog:6,blue:[20,21,23,25,45,50,55,56,62,65,67,68],bmatrix:[6,16,20,51,57,60,65,67,68],boldsymbol:[30,68],boor:36,both:[0,6,52,67,68],bottom:[28,34],bound:28,boundari:[28,40,51,54],box:7,boxplu:68,breadth:49,breast:7,bresenham:28,brown:68,bspline:49,bspline_path:36,bsplinepath:36,bu:[7,16,60,65,67],bu_k:60,bu_t:20,bug:[1,2,49],build:1,build_doc:1,builder:1,bullet:[7,68],burgard:[6,7,68],c1:36,c2:36,c:[2,6,7,16,36,38,40,60,61,65,68,71],c_0:40,c_1:40,c_2:40,c_:40,c_b_i:5,c_i:36,c_i_b:5,c_sigma1:68,c_sigma2:68,c_sigma3:68,cal_observation_sigma:68,calc:[40,65],calc_chi2:68,calc_control_command:17,calc_curvatur:40,calc_first_deriv:40,calc_innov:67,calc_input:[67,68],calc_jacobian:68,calc_lm_po:67,calc_n_lm:67,calc_normal_vector:31,calc_posit:40,calc_rotational_matrix:68,calc_second_deriv:40,calc_yaw:40,calcul:[6,7,12,17,21,22,29,34,36,41,49,51,67,68,69,71],call:[6,12,34,36,68],camera:32,can:[1,6,7,10,12,17,20,21,23,28,31,34,35,36,38,40,41,51,55,60,65,67,68,69],cancel:17,cancer:7,cannot:[6,7,12,40],captur:67,car:[6,17,41,52,53],care:67,carlon:68,carnegi:34,carri:7,cart:16,cast:[2,29],categor:41,categori:68,caus:7,cccccc:40,cccccccccccccc:5,cd:0,cdot:[6,7,40],cell:[28,30,65,68],center:[21,28,30,31],center_grid_i:30,center_grid_x:30,center_vector:31,certain:[7,32,34],challeng:64,chanc:7,chang:[10,21,34,35,36,65,67,68],chapter:55,character:68,charecterist:6,charg:67,check:[0,1,28,55],chi:68,chi_:68,chi_k:68,children:65,choleski:65,choos:7,chosen:[7,65],ci:1,circl:[2,21,29,53],circleci:1,cla:67,classic:12,classifi:68,clear:1,click:[1,10,12],clim:28,clone:0,close:[28,49],closer:17,closest:[2,70],closur:68,clothoid:[2,49],cloud:[2,29,31],cluster:[2,29,30,34],cm:6,cmap:[6,28],cn:68,co:[12,16,20,28,38,41,57,60,65,67,68],code:[0,2,20,34,35,36,38,40,41,42,47,52,53,54,55,60,65,67,68],coeffici:40,coin:7,collect:[0,2,28,68],collid:55,collis:[42,55],color:[12,17,28,68,71],colorbar:28,column:23,com:[0,5,6],combin:[67,68],come:[60,68],comma:28,command:[7,17,65,68],comment:1,common:[12,72],commun:1,compact:68,compactli:68,compani:1,compar:[17,32,67,68],complet:[6,7,39,67,68],complex:[32,53,54],compon:12,composit:68,comprehend:6,comprehens:41,compromis:32,comput:[7,17,32,41,65,67,68],compute_jacobian:65,compute_weight:65,concept:[6,7,68],concetr:65,concis:[1,67],concret:68,conda:0,condit:[8,40,51,68],condition:7,conf:28,confid:67,configur:[12,17],confus:6,conjug:23,consecut:68,consensu:29,consid:[1,12,31,67,68],consist:[16,30,31,34,41,68],constant:[34,68],constrain:[12,68],constraint:[17,41,57,68],construct:[6,17,28,41,49,68],consumpt:5,contact:1,contain:[5,7,28,67,71],context:68,contin:6,continu:[6,21,35,38,49],contour:6,contourf:6,contrast:68,contribut:[2,68],control:[2,7,9,35,36,51,53,61,62,65,67,68],converg:[65,68],convert:[28,68],convexif:5,convolut:7,coord:12,coordin:[12,16,28,40,65,67,68],copi:[65,68],cork:17,correct:[7,17,65,67],correctli:[7,12],correl:8,correspond:[7,28,67,68],cosin:12,cost:[16,57,60],cotrol:60,could:68,cours:[35,41,44,60,62,67],cov:6,covari:[7,8,20,22,30,65,67,68],covariac:20,cover:67,coverag:[2,49],cow:6,cpoint:28,creat:[0,1,6,17,68],credit:12,cross:[21,25,44,50,53,55,56,62,65,67],crux:7,cset:6,cstride:6,csv:28,cubic:[2,49],cubic_spline_plann:40,cubicsplin:40,cubicspline1d:40,cubicspline2d:40,cumsum:65,current:[1,7,17,21,28,67,68],curv:[6,35,36,38,41,49,52],curvatur:[35,36,38,41,71],cvxpy:[0,60],cx:[16,67],cyan:[44,45,50,53,56],d1:68,d2:[65,68],d:[6,16,21,38,40,41,49,65,67,68],d_1:41,d_2:41,d_3:41,d_:[40,57],d_a:57,d_i:68,d_j:68,d_theta_deg_for_search:34,dare:16,darpa:64,data:[5,6,21,28,31,32,34,40,65,67,68,71],dataset:[6,70],ddot:[6,16,40],ddy:40,de:36,dead:[20,23,65,67,68],deal:6,decomposit:69,decreas:[7,34,65],deepcopi:[65,68],def:[5,6,12,28,36,65,67,68],defect:2,defin:[6,7,12,16,17,40,67,68],definit:[2,16],deg2rad:[41,65,67,68],deg:[34,40],degre:[17,36,60,68],delta:[20,38,57,60,65,67,68],delta_i:17,delta_x:17,deltax:68,den:65,denomin:7,denot:[6,7,68],densiti:30,depend:[0,1,2,8,12,40,68],depth:49,dequ:28,deriv:[12,34,53,68],describ:[1,17,65,67],descript:[1,65],design:[14,22],desir:12,det:[6,65,68],detail:[0,1,2,7,16,55,68],detect:[7,34],determin:[12,17,28,32,34,40,67,68],determinist:[6,65],develop:[0,1],deviat:[6,68],diag:[5,65,67,68],diagon:6,diagram:[7,12],dict:12,didn:7,die:65,dieter:[6,7],diff:17,differ:[7,17,21,34,35,38,65,67,68],differenti:[40,51,57,68],difficult:6,dijkstra:[49,50,56],dimens:[6,17,23,36,40],dimension:[6,32,40,49],dir:[0,1],dir_cosin:5,direct:[12,17,21,34,53,68],directli:[12,68],directori:0,discrep:68,discret:[16,21,28,60],discretis:28,discrimin:24,discuss:68,disk:29,displac:12,displai:[5,7,28],displaystyl:7,dist:28,distanc:[2,12,17,21,23,28,29,31,32,34,35,38,40,41,45,65,67,68,71],distribut:[21,29,32,34,65,68],div:5,dn:[65,67,68],doc:1,docstr:1,document:[0,6,31,60],doe:[6,15,21,31,32,55],doesn:[7,67],dof:[5,17],domain:53,donat:1,done:[30,65,67,68],door:7,doorwai:7,dot:[16,20,57,60,65,67],doubl:[47,53],down:[12,17],download:68,dr:67,draw:12,draw_angl:12,drawn:65,drewtu2:67,drive:[6,17,53,58,59,62,63,67],drone:[2,3],ds:40,dt:[17,60,65,67,68],dta:60,dtb:60,dtype:[32,67],du:16,du_:60,dubin:[2,49],dubins_path_plann:41,dubinspath:41,due:[7,21],dure:[1,12,65,68],dx:[6,7,12,65,67,68],dy:[40,65,67],dynam:[2,44,49,60],dz:65,e:[6,7,17,28,41,65,67,68],e_:68,e_j:68,e_x:6,each:[0,1,2,6,7,20,21,28,30,32,34,36,40,41,45,51,55,65,67,68],earlier:[65,68],eas:0,easi:[1,2,7,28],easier:[12,67],easili:[17,68],east:28,eb6d1cbe6fc90c7be9210bf153b3a04f177cc138:60,ece452:37,edg:[34,68],edges_odom:68,edges_scan:68,effect:[17,65,68],effector:[10,12],effici:34,eig_valu:30,eig_vec:30,eigen:30,einsum:6,either:68,ekf:[2,20,24,65,68,70],ekf_slam:67,elbow:12,elbow_i:12,elbow_x:12,element:[6,23,28,36,67],elf:28,ellips:[6,20,30,53],ellipsoid:53,els:[36,65,68],embersarc:5,empti:[6,28,68],encompass:34,end:[5,6,7,10,12,16,20,35,36,38,40,41,51,57,60,65,67,68],end_i:41,end_x:41,end_yaw:41,endpoint:36,enkf:19,ensambl:[2,22],ensur:40,enter:68,entri:68,enumer:34,env:0,environ:[0,1,6,7,12,21,28,39,53,54,68],eq:[51,68],equal:[7,12,17,28,40,41,67,68],equat:[3,7,12,16,17,20,23,36,40,51,57,60,65,67,68],equival:36,error:[1,6,7,17,21,34,67,68],estim:[2,7,20,23,25,29,65,67,68],eta:[2,7,49],eta_j:68,etc:[7,32],euclid:45,euler:[60,68],evalu:34,event:7,everi:[6,67],evid:7,evolv:65,ex:20,exactli:7,exampl:[2,6,8,12,21,26,28,30,31,33,34,36,40,41,65,66,67,69,70],except:65,execut:[0,1,65],exist:[2,21,67],exp:[6,21,30,65,68],expand:55,expans:28,expant:60,expect:[1,67,68],experi:65,experienc:67,explain:[1,17,32],explor:[2,49,68],express:[12,36,40],extend:[2,12,17,22,67],extended_kalman_filt:20,extens:53,extent:68,extern:32,extract:32,ey:67,f1:67,f2:67,f51a73f47cb922a12659f8ce2d544c347a2a8156:60,f:[0,5,6,7,20,28,36,60,65,67,68],f_:7,f_x:7,fac:6,facecolor:12,facilit:68,fact:68,factor:71,fair:7,fake:7,fals:[7,28,36],famili:65,far:[32,67],farther:32,farthest:29,farthest_point_sampl:32,fashion:68,fast:[32,38,45,65],fastslam1:[2,70],fastslam:[2,65,70],feasibl:54,featur:[2,65,66,68],feedback:[2,16,61],field:49,fig:[6,65],figsiz:28,figtext:65,figur:[5,6,28,36,40,55,65,68],file:[1,28,68],file_read:28,filenam:[5,7],fill:[6,28,68],filter:[2,6,8,22,65,67,68],financi:1,find:[1,12,17,45,55,67,68],first:[1,7,12,28,30,34,49,60,68],firstli:68,fit:[2,29,30,38],five:40,fix:[2,68],flip:7,flood:28,flood_fil:28,focu:[0,1],focus:53,folder:68,follow:[1,2,3,6,7,23,31,36,38,40,51,65,67,68],fontsiz:68,footstep:14,forc:16,form:[6,7,12,30,67],format:[28,68],formul:[7,51,61,70],formula:[21,36,68],forward:[7,12,52,60,68],forward_kinemat:12,found:68,fox:[6,7],fpf:7,frac:[5,6,7,12,16,20,21,23,30,31,36,38,40,57,60,65,67,68],frame:[2,49,67],free:[1,5,28,55],freedom:[17,68],frenet:[2,49],fresnel:49,fring:28,frm:55,from:[1,5,6,7,12,16,17,20,22,25,28,31,32,34,35,36,40,41,51,55,60,65,67,68,71],fuel:5,full:68,fulli:[58,68],funciton:65,further:68,fusion:[19,20,23,24],futur:7,fx:[7,65,67],fx_t:20,g1:38,g2o:68,g:[6,16,17,20,28,41,49,67,68],g_i:5,g_odom:68,g_scan:68,g_x:41,g_y:41,g_yaw:41,gain:[8,17,67],gamma:12,gather:6,gaussian:[2,7,8,21,29,65,68],gca:[6,28],gco:16,gener:[0,2,3,6,8,20,28,32,34,35,36,40,41,43,44,49,54,68],generate_ray_casting_grid_map:28,geometr:53,geometri:12,get:[1,2,6,7,12,17,20,21,35,40,51,60,65,68],get_h_b:68,get_lm_pos_from_st:67,ghliu:52,gif:[1,65],gird:21,git:0,github:[0,1,2,5],give:[6,7,12,28,68],given:[6,7,12,17,28,40,65,67,68],gm:16,gmre:[2,61],gnss:20,go:[0,1,12,17,67,68],goal:[0,1,10,12,17,38,41,53,55,68],goe:[12,52],good:[32,57],govern:17,gp:[20,67,68],grand:64,graph:[1,2,36,50,53,56,70],graph_based_slam:68,graphics_radiu:68,graphslam:68,graviti:5,great:1,greater:[31,32],green:[20,28,53,62,67],grid:[2,21,29,30,32,40,41,49,65,67,68],grid_index_map:30,grind:21,gripper:12,grisetti2010tutori:68,grisetti:68,ground:[65,67,68],grow:67,guess:7,guid:53,gyro:20,gz:65,h:[7,20,21,57,67,68],h_:40,h_i:40,h_t:67,ha:[6,7,20,21,28,40,41,65,66,68],had:[7,65],hallwai:7,hamiltonian:57,han:28,hand:7,handi:28,happen:1,hat:[65,68],have:[1,6,7,12,30,32,34,65,67,68],head:[7,17,36,40,71],header:1,heading_list:71,heat:45,height:6,help:[1,7,12,17,68],henc:[6,7,12],here:[6,7,28,36,67],hermit:38,heurist:[45,53],hf:65,hi:68,high:[23,28,54,67],higher:[1,17,21],highest:[6,65],hist:[6,65],histogram:[2,7,22],histori:[2,65,67,68],hline:7,hobbi:1,hold:[7,65,68],holonom:15,horizont:[16,34,68],how:[2,6,7,15,22,28,55,65,67,68],howev:[7,10,31,65,67,68],hphantom:68,hspace:65,hstack:[65,67,68],html:[5,65],http:[0,5,6,12],hv:65,hx_:20,hxdr:[67,68],hxest:67,hxtrue:[67,68],hybrid:[2,49],hz:68,i:[1,2,7,8,12,17,20,23,36,40,60,65,67,68],i_:40,i_j:23,i_k:23,icp:[2,70],id1:68,id2:68,id:[1,21,34,67,68],id_set:34,idea:[0,2,17,68],ident:[12,67,68],ieee:[28,68],ignor:12,ii:6,ij:[6,68],illustr:68,imag:[5,7,28],immateri:7,implement:[5,12,20,52,57,60,65,67,68],implicit:53,imposs:6,improv:[7,23,45,68],imshow:[28,68],imu:68,includ:[0,1,12,17,20,31,34,55,65,67,68],incorpor:[7,67,68],increas:[6,7,34,40,65],increment:[17,53],ind:[65,67],independ:[6,8,17,65,68],index:[2,30,65,67],indic:[65,68],industri:0,inertia:5,inf:[6,68],infom:20,inform:[1,6,7,21,23,41,49,55,67,68],infti:6,init_print:5,initi:[7,16,28,34,41,60,65,67,68],initp:67,inlier:31,inlier_dist:31,inlier_radio_th:31,inlin:[12,65,68],innermost:6,innov:67,input:[6,7,20,21,36,40,57,60,65,67,68],input_intel:68,insert:68,insight:65,inspir:5,instal:0,instanc:7,instanti:17,instead:[12,68],institut:34,int_:[6,38],integr:[47,49,53],intellig:68,interact:[10,12,65],interest:65,interpol:[38,40,49],interpolate_b_spline_path:36,interv:[20,34,40],intial:65,introduc:7,introduct:[2,8,69,70],intslid:65,intuit:[0,65,67],inv:[6,65,67,68],invers:[9,68],invert:[2,15],involv:[6,12],ip:65,ipython:[5,7,65],ipywidget:65,irion:68,issu:[1,32],item:1,iter:[2,7,28,31,32,67,68,70],itertool:68,ith:6,its:[6,7,12,17,32,38,41,45,53,67,68],itself:[7,12],ix:[36,40],iy:40,iyaw:40,iz1:68,iz2:68,iz:[65,67],j:[6,16,23,40,57,68],j_b:5,j_f:20,j_g:20,jacob_mot:67,jacobh:67,jacobian:[5,20,67,68],jame:40,jeff:68,jetbrain:1,jf:67,join:41,joint:[2,9],joint_angl:12,jth:6,judg:34,just:[1,6,7,12],k:[2,6,7,12,16,20,23,29,36,40,60,67,68,71],k_p:17,k_th_t:67,kalman:[2,6,8,22,67],kappa:[38,40],keep:[1,32],keesl:40,kei:7,kf:[2,8],kh:7,kick:7,kind:40,kinemat:9,kl:6,knot:36,know:[7,12,67],known:[12,21,40,51,65,67,68],ko:12,kp_alpha:17,kp_beta:17,kp_rho:17,kp_x:17,kp_y:17,kummerl:68,ky:[7,20],l0:12,l1:12,l:[6,7,16,28,34,38,41,60,68],l_0:12,l_1:12,l_1co:12,l_1sin:12,lab:60,labb:[6,7],label:[1,6,36,40,41,68,71],label_diagram:12,lagrang:16,lambda_1co:57,lambda_1vco:57,lambda_1vsin:57,lambda_2sin:57,lambda_2vco:57,lambda_2vsin:57,lambda_3:57,lambda_4:57,lambda_4u_a:57,land:[2,3],landmark:[23,65,67,68],lane:49,languag:[1,12],larg:[31,32,68],larger:[6,31,68],largest:65,laser:[28,34],last:67,lastli:17,later:71,lattic:[2,48,49],law:[6,8,12,16],lco:60,ldot:68,lead:[12,68],learn:[2,32],least:[1,31,41,67,68],lectur:65,left:[5,6,7,10,12,21,30,38,40,41,67,68,71],legend:[6,40,41,68],len:[36,65,67,68],length:[12,16,38,40,41],leq:[36,57],less:[31,32,36,65],lesson:12,let:[1,7,12,28,68],lg:28,li:68,librari:[0,1,12],licens:1,lidar01:28,lidar:[2,29,32,68],lidar_to_grid_map:28,lie:7,lieu:68,like:[0,1,6,7,21,30,32,55,65],likelihood:[7,68],linalg:[6,65,67,68],linalgerror:65,line:[17,20,23,24,28,39,40,41,44,50,53,55,56,62,65,67,68,71],linear:[2,16,17,40,51,61,65,67,68],linearli:[38,60],linewidth:[6,12,28],link:[9,16],link_length:12,linspac:[6,36,40,65],list:[6,30,36,40,41,68,71],lite:49,literatur:68,littl:67,ll:[6,12],lm:[65,67],lm_id:65,lm_size:[65,67],lmid:[65,67],lmp:65,load:[16,68],load_g2o_se2:68,loc:6,local:[1,2,8,51,53,68,70],locat:[6,7,65,67,68],logic:17,look:[7,21,65,68],lookup:49,loop:[49,68],lose:7,lost:7,low:[65,67],lower:[6,65,68],lowest:65,lqr:[2,15,49,61],lrl:41,lshapefit:34,lsl:41,lsr:41,luca:68,m:[5,16,30,32,34,40,41,65,67,68],m_dist_th:[65,67],m_k:68,machin:32,made:67,magazin:68,magic:7,magnitud:71,mahalanobi:[65,67],mahanfathi:53,mai:6,main:[1,36,67,68],maintain:65,maintoolbar:5,major:[6,7],make:[1,6,12,40,68],malaga:68,mammogram:7,manag:21,maneuv:51,manifold:68,manipul:12,manual:1,map1:28,map:[2,7,17,21,31,32,34,45,49,65,67,68,70],map_float:28,mar:5,margin:7,mark:28,markers:[65,68],mass:16,master:[20,60],match:[2,28,68,70],materi:60,math:[6,12,28,65,67,68],mathbb:[6,68],mathbf:[7,30,36,68],mathcal:[7,30,68],mathemat:[1,7,61],mathit:6,mathjax:5,mathop:68,mathrm:[7,38,68],mathsf:[7,68],mathtt:6,matmul:12,matplotlib:[0,6,12,28,40,65,67,68],matri:68,matric:[7,68],matrix:[5,6,20,22,30,40,67,68,69],max:[36,57,60,65,68],max_angular_spe:17,max_it:32,max_itr:68,max_linear_spe:17,max_rang:[65,67,68],maxi:28,maximum:[6,17,21,32,34,41,60,65,67,68],maxx:28,mayb:12,mco:16,mdist:67,mean:[2,6,7,20,21,23,24,28,29,30,32,36,50,56,62,66,68],mean_i:30,mean_x:30,measur:[6,7,23,28,65,67,68],measure_constraint:68,mechan:12,mellon:34,mention:65,menubar:5,merg:[17,32],mesh:6,meshgrid:6,method:[12,28,31,32,34,40,50,53,55,56,64,67],mgrid:6,michael:5,mid:6,might:[1,12,21,32,36],min:[36,60,67,68],min_dist:32,min_dist_of_closeness_criteria:34,min_n_point:30,mind:1,mini:28,minid:67,minim:[16,41,60],minimum:[2,30,32,34,41,60],minor:28,minx:28,miss:[2,7],mit:[6,7],mix:7,ml:16,mlab:6,mm:67,mobil:[24,39,43,48,54,68,69],mod:[17,41],mode:[6,41,57,60],model:[2,6,7,15,21,22,30,34,40,41,46,47,49,53,54,61,65,67,68],model_predictive_speed_and_steer_control:60,modifi:14,modul:[0,1,2,71],moment:5,mono:40,moravec:28,more:[0,2,7,16,34,36,65,67,68],most:12,mostli:68,motion:[6,7,22,45,49,53,54,56,57,62,63,65,67,68],motion_model:[65,67,68],move:[2,6,7,12,15,16,21,68],move_to_pos:17,move_to_pose_robot:17,movement:21,mpc:[15,61],mpl_toolkit:6,mplot3d:6,mu1:6,mu2:6,mu:[6,7,30,65],mu_1:6,mu_2:6,mu_:[6,7],mu_i:6,mu_j:23,mu_k:23,mu_n:6,mu_new:6,mu_p:6,mu_x:6,mu_z:[6,7],much:[6,34,65,67],multipl:[6,7,40,67,68],multipli:[6,7,17,68],multivari:[6,8,67],multivariate_gaussian:6,multivariate_norm:6,must:[12,36,40,67],mx:67,my:1,mypi:0,n1:6,n2:6,n:[2,6,9,28,30,31,32,36,40,65,67,68],n_:23,n_lm:65,n_particl:65,n_path_point:36,n_point:[12,30,32],name:[12,17,68],natur:40,navig:[0,2,17,42,45,54],ncol:65,ndarrai:32,ndt:[2,29],ndt_map:30,ndtgrid:30,ndtmap:30,nearbi:67,nearest:34,necessari:28,need:[12,17,21,28,30,40,68],neff:65,neg:7,neighbour:28,net:12,new_indic:65,next:[1,7,21,28,67,68],ngraphslam:68,nlm:67,node:[40,45,68],nois:[7,20,23,31,65,67,68],noisi:67,noiz:21,non:[15,68],none:[36,40,41],nonlinear:[2,38,61],nonlinear_control:57,norm:[5,6],normal:[2,6,7,17,29,65,68],normal_vector:31,normal_vector_estim:31,normalize_weight:65,north:28,notag:68,notat:68,note:[1,6,7,17,36,67,68],notebook:[5,65,67,68],noth:[6,7],notic:[1,12,65,67],now:[7,12,51,68],np:[5,6,12,28,31,36,40,41,65,67,68],nrow:65,nt:6,nth:65,num:65,num_landmark:67,number:[7,17,28,30,31,32,36,40,65,67,68,71],number_of_nod:68,numer:[6,68],numpi:[0,5,6,12,28,32,40,65,67,68],nx1:67,nx:28,nxn:67,ny:28,o:68,ob:[60,68],object:[2,6,12,16,29,67,68],observ:[22,25,30,31,65,68,70],obstacl:[2,9,28,30,44,45,53],obtain:[32,68],obvious:6,occup:[28,65],occupi:28,occur:7,od:60,odom:68,odometri:68,off:6,offlin:68,offset:[6,12,17,35],offset_yawrate_nois:65,often:68,ok:1,okai:12,old:65,omega:[5,17,20,68],omega_i:65,omega_j:68,omega_t:20,ominu:68,one:[6,7,12,17,31,34,40,41,49,66,68],ones:[28,65,67],onli:[0,1,6,7,16,17,32,65,67,68],onlin:68,ons:68,open:[0,28,59],oper:[32,68],optim:[2,38,49,52,53,54,57,60],optimz:68,option:[36,41],order:[28,40,68],org:[0,20],orient:[17,20,21,28,38,51,68],orig_point:32,origin:[12,34,67,68,71],original_point:32,os:1,oss:[0,1],other:[1,6,7,12,32,38,68],otherwis:36,our:[1,6,7,12,40],out:[17,65,68],outlier:31,output:[6,17,41,65,68],outsid:[40,67],outward:55,over:[6,67,68],overdetermin:68,overlin:7,overview:1,ox:[28,30,34],oy:[28,30,34],p102:17,p1:31,p2:31,p3:31,p:[6,7,12,16,17,31,36,41,65,67,68],p_1:31,p_2:31,p_3:31,p_:[20,21,67],p_ix_i:6,p_t:[20,21,67],pack:6,packag:28,page:2,pair:68,panel:1,paper:[0,1,2,5,34],parallel:[0,17],param:67,paramet:[5,6,17,30,31,32,34,36,41,49,51,65,67,68,71],parameter:68,pars:68,parse_edg:68,part:[2,8,40,67,68],partial:[20,57,60,68],particl:[2,22,65,68],particular:[67,68],partwai:7,pass:[36,40,65,67],past:7,patch:6,path:[2,12,17,36,40,44,45,46,50,51,52,54,56,58,59,60,62,63,64,68,71],path_finder_control:17,path_i:41,path_x:41,path_yaw:41,pathfindercontrol:15,pathplan:[36,40,41],patienc:1,patreon:1,paug:67,paus:67,paypal:1,peak:[6,7],peaki:21,pendulum:[2,15,53],peopl:1,percent:67,perfect:68,perform:[32,54,67,68],permiss:68,pest:67,pf:[23,65],phase:[53,67],phi1:68,phi2:68,phi:[20,60],phi_:[38,57],phi_a:57,phi_t:20,philosophi:1,pht:65,pi:[6,12,17,21,28,30,41,65,67],pi_2_pi:[65,67,68],pick:[12,65],pid:[53,59,62,63,64],piecewis:36,pip:0,pivot:16,piyg_r:28,plan:[2,12,37,39,45,53,62,63],plan_dubins_path:41,planar:9,plane:[17,31,51],planner:[2,13,41,46,48,49,50,53,56],platform:59,playback:65,pleas:[1,68],plot:[2,6,10,12,28,36,40,41,53,65,67,68,72],plot_arrow:41,plot_curvatur:[36,72],plot_particl:65,plot_surfac:6,plt:[6,12,28,36,40,41,65,67,68],plug:68,pmap:28,png:[5,7],po:6,point:[2,5,9,20,21,24,28,29,30,31,34,35,36,41,45,50,55,56,62,65,68,70],point_cloud_sampl:32,points_3d:31,poisson:29,poisson_disk_sampl:32,polar:49,pole:16,polici:32,polynomi:[2,36,40,49],pop:28,popul:[6,68],popular:28,pose:[2,15,38,41,65,67],pose_start:17,pose_target:17,posit:[1,6,7,10,12,15,16,20,30,34,36,40,41,51,53,60,65,67,68,71],possibl:[6,7,12,32,34,41,68],post:1,posterior:[6,7,68],postion:17,potenti:49,power:[2,3,65],pr:[1,7],practic:[0,1,2,6,68],pragma:67,precis:68,pred:20,predict:[2,7,20,44,49,53,54,61,70],predict_particl:65,prescrib:41,presenc:7,present:[7,17,68],press:[6,7],previou:[7,34,68],primarili:67,prime2:40,prime:[38,40],print:[6,65,67,68],prior:[6,7],prm:[2,49],probabilist:[2,6,8,20,21,28,49,65,66,67,68],probabilit:6,probabl:[6,7,30,31,65,68],problem:[1,12,31,54,67],proc:28,proceed:68,process:[1,7,20,21,23,32,65,67],prod_:68,profil:51,program:[12,17],project:[0,2,6,68],prone:6,propag:68,proper:17,properti:[7,8],proport:[17,34],propos:1,propto:68,provid:[1,17,21,36,55,65,67],psi_i:68,psi_j:68,pure:[2,53,61],pursuit:[2,53,61],put:6,pw:65,px:65,py:[1,17,20,28,60,68],pyplot:[6,12,28,40,65,67,68],pyreedsshepp:52,pytest:0,pythagorean:12,python3:0,python:[0,1,2,5,68],pythonrobot:[0,20,32,60,72],q0:5,q1:5,q2:5,q3:5,q:[5,7,16,20,60,65,67,68],q_:5,q_f:60,q_t:67,q_w:68,q_x:68,q_y:68,q_z:68,qiita:57,qquad:17,qsim:[65,67,68],quad:36,quadcontourset:6,quadrat:[2,61],quadrotor:4,quaternion:68,question:67,queue:28,quintic:[2,49],quit:17,r0:34,r:[0,7,12,16,20,38,40,41,60,65,67,68],r_0:34,r_:[34,36],r_d:[34,60],r_t_b:5,rad2deg:40,rad:[28,41,65,67],radian:28,rai:[2,28,29],rajamani:60,rajesh:60,rand:[6,65],randam:29,randn:[6,65,67],random:[2,7,31,32,49,65,67,68],randomli:[31,32],rang:[6,12,17,21,25,28,29,36,40,65,67,68],ransac:29,ransac_normal_vector_estim:31,rapidli:[2,49],rate:38,ratio:[31,67],raw:67,rd:[21,34],re:[12,65],read:[2,7,28,67,68],readabl:0,readi:1,readm:1,real:[5,6,28,32,53,67,70],realist:68,realli:6,rear:[2,61],reckon:[20,23,65,67,68],recognit:[2,29],record:65,recov:68,rect:34,rectangl:[2,29],rectangle_fit:34,rectangular:34,rectilinear:68,recurs:36,red:[20,21,23,25,28,44,50,53,55,56,62,65,67,68],reduc:32,reed:[2,49],ref:[22,35,43,44,45,48,50,52,54,56,60,61],refer:[3,8,15,22,29,49,61,70],reflect:21,regard:68,regul:[2,61],regular:[7,21,32],rel:[12,65,67,68],relat:[1,6,12,68],relationship:17,remain:[7,12],remov:55,rep:68,repeat:[6,31,68],replac:32,replan:45,repo:[0,6,7,68],report:2,repres:[7,21,28,32,36,40,65,67,68],represent:[7,28,30,40],requir:[1,2,68],resampl:70,resampleid:65,rescal:28,reseampl:65,reshap:[6,65],residu:[7,68],resolut:[28,30],respect:[7,17,51,65,67],respons:12,restructuredtext:1,result:[7,30,36,41,65,67,68],rf:21,rfid:[21,23,65,67,68],rh:7,rho:17,rho_1:57,rho_1d_a:57,rho_1u_a:57,rho_2:57,rho_2d_:57,rho_2u_:57,riccati:16,right:[5,7,12,21,30,34,38,40,41,68,71],rightarrow:7,rk:40,rlr:41,ro:28,road:[2,17,49],roadmap:50,robot:[0,1,2,6,7,9,15,20,21,23,24,28,34,39,43,45,48,49,53,54,56,64,65,66,67,68,69],robotacademi:12,robust:[21,31],rocket:[2,3],rod:16,roger:[6,7],rotat:[17,34,68,69],rough:[48,54],routin:36,row:23,rrt:[2,49],rrtstar:53,rsim:[65,67,68],rsl:41,rsr:41,rst:1,rstride:6,rt1:68,rt2:68,ruff:0,rule:[8,68],run:[1,65,68],runtest:1,rv:6,rx:[5,40],ry:[5,40],ryaw:40,rz:5,s:[1,7,12,16,20,21,28,34,36,38,40,41,45,65,67,68],s_:40,s_j:40,s_x:41,s_y:41,s_yaw:41,sai:7,sakai:67,same:[6,7,12,21,24,32,34,66,68],sampl:[0,1,2,6,29,35,38,40,41,42,47,49,50,52,53,60,65],save:68,scale:[7,68,71],scan:68,scanner:34,scenario:[7,44],schol:65,scholinv:65,scipi:[0,6,36],scipython:6,scope:68,screenshot:1,script:[0,1,54],scriptstyl:68,se:70,search:[2,29,49,50,53,56],search_correspond_lm_id:67,sebastian:[6,7],second:[7,12,34],secondli:68,section:[17,32],see:[0,2,7,16,17,28,65,67,68],seed:[32,68],seek:68,seen:68,segment:[29,38,41],select:[0,2,7,31,32,34,41],selected_typ:41,self:[12,62,63,65],sens:[6,7],sensor:[6,7,19,20,21,23,24,25,32,34,65,67],separ:[28,40],seper:6,sequenc:68,seri:7,set:[6,10,12,17,21,31,34,65,67,68],set_printopt:68,set_start_target_pos:17,set_titl:65,set_xtick:28,set_ytick:28,set_zlim:6,set_ztick:6,setup:1,sever:12,sf:65,sh:1,shall:68,shape:[2,6,28,29,65,67,68],share:1,sheep:49,shepp:[2,49],shift:[7,21],shortest:[41,45],should:[1,67,68],shoulder:12,show:[1,6,7,12,21,28,30,36,40,41,45,65,67,68,71],show_anim:67,shown:[7,12,16,40,65,67],shrink:12,shunichi09:57,side:[6,34,67,71],sig:65,sigma:[6,7,30,60,67,68],sigma_1:[6,7],sigma_2:[6,7],sigma_:[6,7,67],sigma_det:6,sigma_inv:6,sigma_n:6,sigma_p:6,sigma_v:[65,67],sigma_w:[65,67],sigma_x:[6,7],sigma_z:[6,7],sign:12,signal:67,signifi:34,sim:30,sim_tim:[65,67,68],similar:68,similarli:[6,68],simpl:[1,28,36,41,46,53,68],simpli:[6,12,67],simplic:68,simplifi:[5,67,68],simul:[0,1,3,4,10,11,12,17,20,21,24,39,58,59,60,62,63,64,66,68,70],simultan:[17,70],sin:[12,16,20,28,38,41,57,60,65,67,68],sinc:[6,7,12,68],singl:[6,38,65,67,68],singul:65,singular:[68,69],situat:32,six:[41,68],size:[6,12,28,32,41,65,67,68],skew:5,slam:[2,65,66],slide:57,slipperi:17,slow:17,small:[16,68],smaller:[7,31,34,36],smallest:34,smooth:[17,36,40,43],smoother:36,smoothli:[36,40],snippet:[65,68],so:[6,12,16,20,21,32,36,40,51,57,60,68],softwar:[0,2],solut:[12,16,68],solv:[1,12,32,40,49,51,54,68],solver:[38,68],some:[0,1,6,7,28,34,68],someon:1,someth:6,sonar:28,sort:40,sourc:[0,30,31,32,34,36,40,41,68,71],south:28,sp:[5,40],space:[6,16,21,31,32,40,54,68],span:49,sparser:34,specif:[17,67],specifi:[12,32],speed:[2,17,20,21,53,59,61,62,63,64],sphinx:[0,1],spiral:49,spline:[2,49],split:[28,68],spread:[6,65],springer:60,springerlink:17,sq:67,sqrt:[5,6,12,17,21,30,65,67],squar:[31,34,67,68],squre:34,srate:65,stachniss:68,stage:67,standard:[0,6,68],stanlei:[2,61],star:[0,2,45,49,67,68],start:[1,2,17,28,35,38,40,41,51,53,55,65,67],start_i:41,start_x:41,start_yaw:41,stat:6,state:[2,7,16,20,23,48,49,51,60,65,67,68],state_s:[65,67,68],stc:39,steelblu:68,steer:[2,53,61,62,63,64],step1:[29,49],step2:[29,49],step3:49,step:[6,7,17,20,21,29,31,34,41,65,68,70],step_siz:41,still:51,stochast:6,stop:[28,31],store:67,stori:6,str:65,straight:[28,41,71],straightforward:[17,68],street:44,string:[17,41,71],structur:[8,68],style:[0,1,5],subdirectori:1,subject:[16,60,68],subplot:[28,40,65,68],subplots_adjust:65,subset:68,succeed:1,success:[1,5],successiveconvexificationfreefinaltim:5,suffici:68,suggest:7,suit:1,suitabl:32,sum:[6,7,23,30,65,68],sum_:[6,36,68],summat:36,sumw:65,support:2,suppress:68,surfac:6,surpris:68,surround:67,survei:[62,63],surviv:65,sw:65,sweep:49,sx:28,sy:28,symbol:5,symmetr:67,sympi:5,system:[7,15,16,58,65,67,68],szmuk:5,t1:68,t2:68,t:[6,7,12,16,20,21,30,36,41,51,60,65,67,68],t_:36,t_i:[36,68],tabl:49,take:[6,7,17,34,67],taken:67,tan:[12,40,57,60],tangent:[12,41],tangle1:68,tangle2:68,target:[17,44,60,62],task:68,tau:38,tayer:60,tbd:18,tech:68,techniqu:[32,62,63,68],tell:[6,12],tend:[6,34],term:[7,12,17],termin:[41,51],terrain:[45,48,54],tesla:6,test:[0,1,7,67],test_a_star:1,test_codestyl:1,text:[7,36,68],textbf:20,th:[23,34,40],than:[7,12,31,32],thei:[1,6,7,28,65],them:[6,68],theorem:[7,12],theoret:67,theori:68,therefor:[6,7,67,68],theta0:12,theta1:12,theta:[12,16,17,40,41,57,65,67,68],theta_0:12,theta_1:12,theta_:[17,51,65,67],theta_engin:17,theta_go:17,theta_i:68,theta_j:68,theta_steering_wheel:17,thi:[2,4,6,7,10,12,16,17,19,20,21,23,24,25,26,27,28,30,31,32,33,34,36,37,38,39,40,42,43,44,45,46,48,50,53,54,55,56,60,65,66,67,68,69,71],thin:32,thr:30,threashold:34,three:[7,17,32,34,68],threshold:[31,34,65,67],through:[7,36,40,68,70],throught:68,thrun:[6,7],thrust:5,thu:[17,68],thumb:1,tick:[6,65,67,68],tight_layout:65,till:68,tim:66,time:[1,5,6,7,12,16,17,20,21,31,32,51,53,60,65,67,68],timestep:68,titl:[36,68],tmp1:68,tmp2:68,tmp3:68,tmp4:68,todo:68,togeth:[6,36],too:[6,7],tool:60,top:[1,16,28,34],toss:7,total:[6,7],toward:[17,21,58,68],tparticl:65,tpg:67,trace:28,track:[2,7,58,59,60,63,64,67],train:24,trajectori:[2,3,20,23,49,54,65,67,68],transform:[2,29,68],transform_point:12,transit:[7,67],translat:[17,69],transport:68,transpos:5,travel:68,travers:68,tree:[2,49],triangl:[12,29],trigonometr:12,trust:[65,67],truth:[65,67,68],tu:67,tune:17,tupl:36,turn:[7,17,41,71],tutori:[28,41,68],twice:7,two:[2,6,7,9,17,21,28,30,32,36,38,40,41,49,55,67,68],twolinkarm:12,txt:0,type:[0,31,32,36,40,41,68],typic:68,u:[5,7,16,17,20,57,60,65,67,68],u_:[7,57,60],u_a:57,u_k:60,u_t:[7,60,68],ubar:60,uc:60,uco:16,ud1:65,ud2:65,ud:[65,67,68],ukf:[24,68],unari:68,uncertain:21,uncertainti:[65,67],under:[1,6],underbrac:68,underset:68,understand:[0,1,2,67],uniform:[6,49,65],uniformli:[65,68],uniqu:[16,68],unit:[0,1,67],univari:8,univariatesplin:36,univers:[34,68],unknown:[21,28,45,51,68],unlik:[7,65],unobserv:28,unscent:[2,22],unstructur:39,until:[31,32,68],up:[1,6,12,65,67],updat:[6,7,20,68,70],update_joint:12,update_kf_with_choleski:65,update_landmark:65,update_with_observ:65,upper:[6,36],urban:[21,53,62,63,68],us:[1,2,6,7,12,16,17,20,21,23,28,29,30,31,32,36,38,40,41,45,47,48,50,51,53,54,56,60,65,66,67,68],usag:1,use_latex:5,user:[1,36],usual:68,util:[2,36],ux:5,uy:5,uz:5,v1:31,v2:31,v:[5,17,20,57,60,65,67,68],v_:[51,60,65,67],v_e:51,v_eco:51,v_esin:51,v_i:68,v_sco:51,v_ssin:51,v_st:51,v_t:[20,60,67],valid:68,valu:[6,7,12,16,17,21,28,30,31,34,36,45,65,67,68,69],var_new:6,vari:6,variabl:68,varianc:[7,8,65],variance1:6,variance2:6,variant:68,variat:[6,67],vartheta_:38,vco:[57,60],vdot:[6,40,67,68],vec:17,vecor:20,vector:[2,5,6,7,12,20,29,30,36,55,60,67,68,69],vehicl:[21,34,35,46,53,61,62,63],veloc:[7,17,20,51,60,65,67],veri:[32,65],versa:67,version:1,vertex:[55,68],vertex_id:68,vertic:[16,17,34,55,68],via:[1,53,68],vice:67,vicin:17,view:[6,68],view_init:6,viridi:6,virtual:68,visibl:[2,49],vision:17,visual:[6,68],vornoi:56,voronoi:[2,49],voxel:29,voxel_point_sampl:32,voxel_s:32,vsin:[57,60],vstack:67,vtan:60,vulner:31,vx:5,vy:5,vz:5,w1:65,w:[5,17,20,23,28,65,67,68],w_1:7,w_2:7,w_:[65,67],w_i:65,w_t:67,wa:[1,7,68],wai:[1,6,7,21,31,68],walk:[14,68,70],want:[1,7,12,21,32,68],wavefront:49,waypoint:[36,40],wb:57,wcum:65,we:[7,12,17,21,28,30,31,34,38,40,51,55,65,67,68],websit:68,weight:[6,7,21,23,36,65],welcom:60,well:[17,40,55,67,68],were:[7,67],west:28,what:[1,2,7,12,68],wheel:[2,17,43,48,54,61],when:[1,7,16,17,21,30,31,36,40,51,55,68],where:[7,12,16,20,31,32,34,38,40,41,60,65,67,68],wherea:68,whereabout:7,which:[0,6,7,12,28,31,32,34,36,38,40,41,65,67,68],why:68,wide:[0,1,2,28],widget:65,width:[5,7],wikipedia:[36,41,45,50,55],wildcard:68,window:[2,49],wise:6,within:[34,67],without:[1,7,21,32],wolfram:[6,7],women:7,won:64,word:[38,68],work:[1,7,15,28],world:[6,67,70],would:[1,6,7,12],wrist:12,wrist_i:12,wrist_x:12,write:[12,28,68],written:[0,1,12],wrong:[12,65],wx:5,wy:5,wz:5,x1:[6,68],x2:[6,68],x3:6,x:[0,5,6,7,12,16,17,20,21,23,28,30,31,34,36,38,40,41,49,57,60,65,67,68,71],x_1:[6,65,67],x_2:[6,65,67],x_3:6,x_:[7,17,20,38,40,41,51,65,67,68],x_cor:6,x_diff:17,x_e:[41,51],x_end:12,x_i:[6,68],x_j:[40,68],x_k:6,x_list:[41,71],x_n:[65,67],x_nx:67,x_nx_1:67,x_nx_2:67,x_nx_n:67,x_ny:67,x_ny_1:67,x_ny_2:67,x_ny_n:67,x_opt:68,x_po:65,x_pos2:65,x_start:12,x_state:67,x_t:[6,7,20],x_true:68,x_y:67,xaug:67,xb:40,xd:[65,67],xdist:0,xdr:[65,67,68],xe:51,xest:[20,67],xf:65,xg:67,xi:[23,40,68],xi_:23,xlabel:[40,65],xlim:6,xlist:68,xm:67,xs:51,xtrue:[65,67,68],xupdat:67,xx:67,xx_1:67,xx_2:67,xx_n:67,xy:[6,12,67],xy_1:67,xy_2:67,xy_n:67,xyre:28,xyreso:28,xytext:12,y1:68,y2:68,y:[6,7,12,16,17,20,21,28,30,31,34,36,38,40,41,49,57,60,65,67,68,71],y_1:[65,67],y_2:[65,67],y_:[17,38,40,51,65,67],y_cor:6,y_diff:17,y_e:51,y_i:[40,68],y_j:[40,68],y_list:[41,71],y_n:[65,67],y_t:20,yaw1:68,yaw2:68,yaw:[21,28,38,40,41,60,65,67,68],yaw_list:41,yawrat:[65,67],yawreso:28,ye:[12,51],yellow:28,yet:7,yi:40,yield:68,ylabel:[40,65],ylim:28,yml:0,you:[0,1,7,10,12,17,32,34,35,36,40,41,51,55,60],your:[1,7,17],ys:51,yx:67,yx_1:67,yx_2:67,yx_n:67,yy:67,yy_1:67,yy_2:67,yy_n:67,z1:68,z2:68,z:[6,7,20,21,31,60,65,67,68],z_0:60,z_:[7,20,60],z_i:65,z_k:60,z_ref:60,z_t:[6,7,65,67],zangl:67,zbar:60,zdir:6,zero:[5,6,28,65,67,68],zerodivisionerror:65,zeros_lik:36,zi:[65,67],zid:68,zlist:68,zp:[65,67]},titles:["Getting Started","How To Contribute","Welcome to PythonRobotics\u2019s documentation!","Aerial Navigation","Drone 3d trajectory following","Rocket powered landing","KF Basics - Part I","KF Basics - Part 2","Appendix","Arm Navigation","N joint arm to point control","Arm navigation with obstacle avoidance","Two joint arm to point control","Bipedal","Bipedal Planner","Control","Inverted Pendulum Control","Move to a Pose Control","Introduction","Ensamble Kalman Filter Localization","Extended Kalman Filter Localization","Histogram filter localization","Localization","Particle filter localization","Unscented Kalman Filter localization","Object shape recognition using circle fitting","Gaussian grid map","k-means object clustering","Lidar to grid map","Mapping","Normal Distance Transform (NDT) map","Normal vector estimation","Point cloud Sampling","Ray casting grid map","Object shape recognition using rectangle fitting","Bezier path planning","B-Spline planning","Bug planner","Clothoid path planning","Coverage path planner","Cubic spline planning","Dubins path planning","Dynamic Window Approach","Eta^3 Spline path planning","Optimal Trajectory in a Frenet Frame","Grid based search","Hybrid a star","LQR based path planning","Model Predictive Trajectory Generator","Path Planning","Probabilistic Road-Map (PRM) planning","Quintic polynomials planning","Reeds Shepp planning","Rapidly-Exploring Random Trees (RRT)","State Lattice Planning","Visibility Road-Map planner","Voronoi Road-Map planning","Nonlinear Model Predictive Control with C-GMRES","Linear\u2013quadratic regulator (LQR) speed and steering control","Linear\u2013quadratic regulator (LQR) steering control","Model predictive speed and steering control","Path Tracking","Pure pursuit tracking","Rear wheel feedback control","Stanley control","FastSLAM1.0","FastSLAM 2.0","EKF SLAM","Graph based SLAM","Iterative Closest Point (ICP) Matching","SLAM","Plotting Utilities","Utilities"],titleterms:{"0":[65,66],"1":[1,34,40,65,67],"1d":40,"1st":7,"2":[1,7,34,40,65,66,67,68],"2d":40,"2nd":7,"3":[1,34,40,43,65],"3d":[4,31],"4":[1,40],"5":[1,40],"class":17,"do":6,"function":[17,38],"new":1,A:45,Of:18,The:68,To:1,a_j:40,about:1,ad:1,adapt:34,add:1,advantag:6,aerial:3,algorithm:[1,7,17,18,21,45,55,65,67,68],an:1,anim:1,api:[30,31,32,34,36,40,41],appendix:8,applic:18,approach:42,approxim:36,area:34,arm:[9,10,11,12],avoid:11,b:36,b_j:40,base:[1,39,45,47,55,68],basic:[6,7,36,53],batch:53,bay:7,belief:6,bezier:35,bias:54,bidirect:45,biped:[13,14],breadth:45,bspline:36,bug:37,c:57,c_j:40,calcul:[23,31,38,40],cast:33,central:6,choos:1,circl:25,close:[34,53],closest:69,clothoid:38,cloud:32,cluster:27,code:1,condit:7,connect:55,consensu:31,constraint:40,construct:38,constructor:17,content:[2,3,8,9,13,15,22,29,49,61,70,72],continu:40,contribut:1,control:[10,12,15,16,17,57,58,59,60,63,64],correl:6,covari:[6,23],coverag:39,criteria:34,cubic:40,curv:40,curvatur:40,d:45,d_j:40,dataset:68,defect:1,definit:18,depend:7,depth:45,deriv:40,describ:6,design:20,dijkstra:[45,55],dimension:[51,68],disk:32,distanc:30,distribut:[6,30],document:[1,2],doe:17,drone:4,dubin:[41,53],dynam:42,ekf:67,ensambl:19,equat:5,estim:[21,31],eta:43,exampl:[1,7,68],exist:1,expect:6,explor:53,extend:20,farthest:32,fastslam1:65,fastslam:66,feedback:63,field:45,filter:[7,19,20,21,23,24],first:[40,45],fit:[25,34],fix:1,follow:4,formul:[57,68],frame:44,frenet:44,fresnel:38,from:[21,23],g:38,gain:7,gaussian:[6,26],gener:[5,7,48,55],get:0,gmre:57,graph:[55,68],grid:[26,28,33,39,45],histogram:21,histori:18,holonom:17,how:[0,1,17,23,40],hybrid:46,i:6,icp:69,implement:1,independ:7,indic:2,inform:53,initi:21,integr:38,interpol:36,introduct:[6,18,65,67,68],invers:12,invert:16,iter:69,joint:[10,12],k:27,kalman:[7,19,20,24],kf:[6,7],kinemat:12,land:5,lane:54,lattic:54,law:7,learn:18,lidar:28,limit:6,linear:[58,59,60],link:12,lite:45,local:[7,19,20,21,22,23,24],lookup:48,loop:53,lqr:[16,47,53,58,59],map:[26,28,29,30,33,50,55,56],match:69,mathemat:57,matplotlib:1,matrix:23,mean:27,member:17,minim:[34,68],miss:1,model:[16,20,48,57,60],motion:[20,21,51],move:17,mpc:[16,60],multimod:6,multivari:7,n:10,navig:[3,9,11],ndt:30,need:6,node:55,non:17,nonlinear:57,normal:[30,31],object:[25,27,34],observ:[20,21,67],obstacl:[11,55],one:51,oppos:6,optim:[44,48,68],paramet:[38,40],part:[6,7],particl:23,path:[35,38,39,41,43,47,48,49,53,55,61],pathfindercontrol:17,pdf:6,pendulum:16,plan:[35,36,38,40,41,43,47,49,50,51,52,54,56],planar:[12,68],planner:[14,37,39,55],plot:71,plot_curvatur:71,point:[10,12,32,40,69],poisson:32,polar:54,polygon:55,polynomi:51,pose:[17,68],posit:[17,21],potenti:45,power:5,predict:[21,48,57,60,65,67],prm:50,probabilist:[7,50],probabl:21,problem:68,project:1,properti:6,pull:1,pure:62,pursuit:62,python:18,pythonrobot:2,quadrat:[58,59],quintic:51,rai:33,randam:31,random:[6,53],rang:34,ransac:31,rapidli:53,real:68,rear:63,recognit:[25,34],rectangl:34,reed:[52,53],ref:[20,53,57],refer:[5,6,7,17,21,23,24,34,36,38,40,41,51,55,58,59,60,62,63,64,65,66,67,68,69],regul:[58,59],report:1,repres:6,represent:68,request:1,requir:0,resampl:65,review:1,road:[50,55,56],robot:[12,17,18,51],rocket:5,rrt:53,rule:7,s:[2,6,17],sampl:[31,32,48,54],se:68,search:[34,45,55],second:40,segment:34,shape:[25,34],sheep:53,shepp:52,shortest:55,simul:[5,53,65,67],slam:[67,68,70],softwar:18,solv:38,span:39,speed:[58,60],spiral:39,spline:[36,40,43],sponsor:1,stanlei:64,star:46,start:0,state:54,steer:[58,59,60],step1:[21,34,38,40,55],step2:[21,34,38,40,55],step3:[21,38,40,55],step4:[21,40],step:[1,30,67],structur:7,submit:1,support:1,sweep:39,system:17,tabl:[2,48],tangent:40,term:6,termin:40,theorem:6,thi:[0,1],through:[65,67],track:[61,62],trajectori:[4,44,48],transform:30,tree:[39,53],triangl:31,two:[12,51],uniform:54,unimod:6,unittest:1,univari:7,unknown:40,unscent:24,updat:[21,65,67],us:[0,25,34,55],util:[71,72],variabl:6,varianc:[6,34],vector:[31,40],vehicl:60,visibl:55,voronoi:56,voxel:32,walk:[65,67],wavefront:39,we:6,welcom:2,what:[0,6],wheel:63,why:6,window:42,work:17,world:68,write:1,x:51,y:51}}) \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 3485fe81502..00000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Path hack to make tests work.""" -import sys -import os -import pytest - -TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(TEST_DIR) # to import this file from test code. -ROOT_DIR = os.path.dirname(TEST_DIR) -sys.path.append(ROOT_DIR) - - -def run_this_test(file): - pytest.main([os.path.abspath(file)]) diff --git a/tests/test_LQR_planner.py b/tests/test_LQR_planner.py deleted file mode 100644 index be12195eac2..00000000000 --- a/tests/test_LQR_planner.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.LQRPlanner import lqr_planner as m - - -def test_1(): - m.SHOW_ANIMATION = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_a_star.py b/tests/test_a_star.py deleted file mode 100644 index 82f76401ad2..00000000000 --- a/tests/test_a_star.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.AStar import a_star as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_a_star_searching_two_side.py b/tests/test_a_star_searching_two_side.py deleted file mode 100644 index ad90ebc509a..00000000000 --- a/tests/test_a_star_searching_two_side.py +++ /dev/null @@ -1,16 +0,0 @@ -import conftest -from PathPlanning.AStar import a_star_searching_from_two_side as m - - -def test1(): - m.show_animation = False - m.main(800) - - -def test2(): - m.show_animation = False - m.main(5000) # increase obstacle number, block path - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_a_star_variants.py b/tests/test_a_star_variants.py deleted file mode 100644 index b9ef7914026..00000000000 --- a/tests/test_a_star_variants.py +++ /dev/null @@ -1,44 +0,0 @@ -import PathPlanning.AStar.a_star_variants as a_star -import conftest - - -def test_1(): - # A* with beam search - a_star.show_animation = False - - a_star.use_beam_search = True - a_star.main() - reset_all() - - # A* with iterative deepening - a_star.use_iterative_deepening = True - a_star.main() - reset_all() - - # A* with dynamic weighting - a_star.use_dynamic_weighting = True - a_star.main() - reset_all() - - # theta* - a_star.use_theta_star = True - a_star.main() - reset_all() - - # A* with jump point - a_star.use_jump_point = True - a_star.main() - reset_all() - - -def reset_all(): - a_star.show_animation = False - a_star.use_beam_search = False - a_star.use_iterative_deepening = False - a_star.use_dynamic_weighting = False - a_star.use_theta_star = False - a_star.use_jump_point = False - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_batch_informed_rrt_star.py b/tests/test_batch_informed_rrt_star.py deleted file mode 100644 index 3ad78bdb231..00000000000 --- a/tests/test_batch_informed_rrt_star.py +++ /dev/null @@ -1,14 +0,0 @@ -import random - -import conftest -from PathPlanning.BatchInformedRRTStar import batch_informed_rrtstar as m - - -def test_1(): - m.show_animation = False - random.seed(12345) - m.main(maxIter=10) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_behavior_tree.py b/tests/test_behavior_tree.py deleted file mode 100644 index 0898690448f..00000000000 --- a/tests/test_behavior_tree.py +++ /dev/null @@ -1,207 +0,0 @@ -import pytest -import conftest - -from MissionPlanning.BehaviorTree.behavior_tree import ( - BehaviorTreeFactory, - Status, - ActionNode, -) - - -def test_sequence_node1(): - xml_string = """ - <Sequence> - <Echo name="Echo 1" message="Hello, World1!" /> - <Echo name="Echo 2" message="Hello, World2!" /> - <ForceFailure name="Force Failure"> - <Echo name="Echo 3" message="Hello, World3!" /> - </ForceFailure> - </Sequence> - """ - bt_factory = BehaviorTreeFactory() - bt = bt_factory.build_tree(xml_string) - bt.tick() - assert bt.root.status == Status.RUNNING - assert bt.root.children[0].status == Status.SUCCESS - assert bt.root.children[1].status is None - assert bt.root.children[2].status is None - bt.tick() - bt.tick() - assert bt.root.status == Status.FAILURE - assert bt.root.children[0].status is None - assert bt.root.children[1].status is None - assert bt.root.children[2].status is None - - -def test_sequence_node2(): - xml_string = """ - <Sequence> - <Echo name="Echo 1" message="Hello, World1!" /> - <Echo name="Echo 2" message="Hello, World2!" /> - <ForceSuccess name="Force Success"> - <Echo name="Echo 3" message="Hello, World3!" /> - </ForceSuccess> - </Sequence> - """ - bt_factory = BehaviorTreeFactory() - bt = bt_factory.build_tree(xml_string) - bt.tick_while_running() - assert bt.root.status == Status.SUCCESS - assert bt.root.children[0].status is None - assert bt.root.children[1].status is None - assert bt.root.children[2].status is None - - -def test_selector_node1(): - xml_string = """ - <Selector> - <ForceFailure name="Force Failure"> - <Echo name="Echo 1" message="Hello, World1!" /> - </ForceFailure> - <Echo name="Echo 2" message="Hello, World2!" /> - <Echo name="Echo 3" message="Hello, World3!" /> - </Selector> - """ - bt_factory = BehaviorTreeFactory() - bt = bt_factory.build_tree(xml_string) - bt.tick() - assert bt.root.status == Status.RUNNING - assert bt.root.children[0].status == Status.FAILURE - assert bt.root.children[1].status is None - assert bt.root.children[2].status is None - bt.tick() - assert bt.root.status == Status.SUCCESS - assert bt.root.children[0].status is None - assert bt.root.children[1].status is None - assert bt.root.children[2].status is None - - -def test_selector_node2(): - xml_string = """ - <Selector> - <ForceFailure name="Force Success"> - <Echo name="Echo 1" message="Hello, World1!" /> - </ForceFailure> - <ForceFailure name="Force Failure"> - <Echo name="Echo 2" message="Hello, World2!" /> - </ForceFailure> - </Selector> - """ - bt_factory = BehaviorTreeFactory() - bt = bt_factory.build_tree(xml_string) - bt.tick_while_running() - assert bt.root.status == Status.FAILURE - assert bt.root.children[0].status is None - assert bt.root.children[1].status is None - - -def test_while_do_else_node(): - xml_string = """ - <WhileDoElse> - <Count name="Count" count_threshold="3" /> - <Echo name="Echo 1" message="Hello, World1!" /> - <Echo name="Echo 2" message="Hello, World2!" /> - </WhileDoElse> - """ - - class CountNode(ActionNode): - def __init__(self, name, count_threshold): - super().__init__(name) - self.count = 0 - self.count_threshold = count_threshold - - def tick(self): - self.count += 1 - if self.count >= self.count_threshold: - return Status.FAILURE - else: - return Status.SUCCESS - - bt_factory = BehaviorTreeFactory() - bt_factory.register_node_builder( - "Count", - lambda node: CountNode( - node.attrib.get("name", CountNode.__name__), - int(node.attrib["count_threshold"]), - ), - ) - bt = bt_factory.build_tree(xml_string) - bt.tick() - assert bt.root.status == Status.RUNNING - assert bt.root.children[0].status == Status.SUCCESS - assert bt.root.children[1].status is Status.SUCCESS - assert bt.root.children[2].status is None - bt.tick() - assert bt.root.status == Status.RUNNING - assert bt.root.children[0].status == Status.SUCCESS - assert bt.root.children[1].status is Status.SUCCESS - assert bt.root.children[2].status is None - bt.tick() - assert bt.root.status == Status.SUCCESS - assert bt.root.children[0].status is None - assert bt.root.children[1].status is None - assert bt.root.children[2].status is None - - -def test_node_children(): - # ControlNode Must have children - xml_string = """ - <Sequence> - </Sequence> - """ - bt_factory = BehaviorTreeFactory() - with pytest.raises(ValueError): - bt_factory.build_tree(xml_string) - - # DecoratorNode Must have child - xml_string = """ - <Inverter> - </Inverter> - """ - with pytest.raises(ValueError): - bt_factory.build_tree(xml_string) - - # DecoratorNode Must have only one child - xml_string = """ - <Inverter> - <Echo name="Echo 1" message="Hello, World1!" /> - <Echo name="Echo 2" message="Hello, World2!" /> - </Inverter> - """ - with pytest.raises(ValueError): - bt_factory.build_tree(xml_string) - - # ActionNode Must have no children - xml_string = """ - <Echo name="Echo 1" message="Hello, World1!"> - <Echo name="Echo 2" message="Hello, World2!" /> - </Echo> - """ - with pytest.raises(ValueError): - bt_factory.build_tree(xml_string) - - # WhileDoElse Must have exactly 2 or 3 children - xml_string = """ - <WhileDoElse> - <Echo name="Echo 1" message="Hello, World1!" /> - </WhileDoElse> - """ - with pytest.raises(ValueError): - bt = bt_factory.build_tree(xml_string) - bt.tick() - - xml_string = """ - <WhileDoElse> - <Echo name="Echo 1" message="Hello, World1!" /> - <Echo name="Echo 2" message="Hello, World2!" /> - <Echo name="Echo 3" message="Hello, World3!" /> - <Echo name="Echo 4" message="Hello, World4!" /> - </WhileDoElse> - """ - with pytest.raises(ValueError): - bt = bt_factory.build_tree(xml_string) - bt.tick() - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_bezier_path.py b/tests/test_bezier_path.py deleted file mode 100644 index 67a5d520de8..00000000000 --- a/tests/test_bezier_path.py +++ /dev/null @@ -1,16 +0,0 @@ -import conftest -from PathPlanning.BezierPath import bezier_path as m - - -def test_1(): - m.show_animation = False - m.main() - - -def test_2(): - m.show_animation = False - m.main2() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_bipedal_planner.py b/tests/test_bipedal_planner.py deleted file mode 100644 index 818957bcdcb..00000000000 --- a/tests/test_bipedal_planner.py +++ /dev/null @@ -1,18 +0,0 @@ -import conftest -from Bipedal.bipedal_planner import bipedal_planner as m - - -def test_1(): - bipedal_planner = m.BipedalPlanner() - - footsteps = [[0.0, 0.2, 0.0], - [0.3, 0.2, 0.0], - [0.3, 0.2, 0.2], - [0.3, 0.2, 0.2], - [0.0, 0.2, 0.2]] - bipedal_planner.set_ref_footsteps(footsteps) - bipedal_planner.walk(plot=False) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_breadth_first_search.py b/tests/test_breadth_first_search.py deleted file mode 100644 index bfc63e39d6b..00000000000 --- a/tests/test_breadth_first_search.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.BreadthFirstSearch import breadth_first_search as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_bspline_path.py b/tests/test_bspline_path.py deleted file mode 100644 index 4918c9810f5..00000000000 --- a/tests/test_bspline_path.py +++ /dev/null @@ -1,74 +0,0 @@ -import conftest -import numpy as np -import pytest -from PathPlanning.BSplinePath import bspline_path - - -def test_list_input(): - way_point_x = [-1.0, 3.0, 4.0, 2.0, 1.0] - way_point_y = [0.0, -3.0, 1.0, 1.0, 3.0] - n_course_point = 50 # sampling number - - rax, ray, heading, curvature = bspline_path.approximate_b_spline_path( - way_point_x, way_point_y, n_course_point, s=0.5) - - assert len(rax) == len(ray) == len(heading) == len(curvature) - - rix, riy, heading, curvature = bspline_path.interpolate_b_spline_path( - way_point_x, way_point_y, n_course_point) - - assert len(rix) == len(riy) == len(heading) == len(curvature) - - -def test_array_input(): - way_point_x = np.array([-1.0, 3.0, 4.0, 2.0, 1.0]) - way_point_y = np.array([0.0, -3.0, 1.0, 1.0, 3.0]) - n_course_point = 50 # sampling number - - rax, ray, heading, curvature = bspline_path.approximate_b_spline_path( - way_point_x, way_point_y, n_course_point, s=0.5) - - assert len(rax) == len(ray) == len(heading) == len(curvature) - - rix, riy, heading, curvature = bspline_path.interpolate_b_spline_path( - way_point_x, way_point_y, n_course_point) - - assert len(rix) == len(riy) == len(heading) == len(curvature) - - -def test_degree_change(): - way_point_x = np.array([-1.0, 3.0, 4.0, 2.0, 1.0]) - way_point_y = np.array([0.0, -3.0, 1.0, 1.0, 3.0]) - n_course_point = 50 # sampling number - - rax, ray, heading, curvature = bspline_path.approximate_b_spline_path( - way_point_x, way_point_y, n_course_point, s=0.5, degree=4) - - assert len(rax) == len(ray) == len(heading) == len(curvature) - - rix, riy, heading, curvature = bspline_path.interpolate_b_spline_path( - way_point_x, way_point_y, n_course_point, degree=4) - - assert len(rix) == len(riy) == len(heading) == len(curvature) - - rax, ray, heading, curvature = bspline_path.approximate_b_spline_path( - way_point_x, way_point_y, n_course_point, s=0.5, degree=2) - - assert len(rax) == len(ray) == len(heading) == len(curvature) - - rix, riy, heading, curvature = bspline_path.interpolate_b_spline_path( - way_point_x, way_point_y, n_course_point, degree=2) - - assert len(rix) == len(riy) == len(heading) == len(curvature) - - with pytest.raises(ValueError): - bspline_path.approximate_b_spline_path( - way_point_x, way_point_y, n_course_point, s=0.5, degree=1) - - with pytest.raises(ValueError): - bspline_path.interpolate_b_spline_path( - way_point_x, way_point_y, n_course_point, degree=1) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_bug.py b/tests/test_bug.py deleted file mode 100644 index f94794a45e4..00000000000 --- a/tests/test_bug.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.BugPlanning import bug as m - - -def test_1(): - m.show_animation = False - m.main(bug_0=True, bug_1=True, bug_2=True) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_catmull_rom_spline.py b/tests/test_catmull_rom_spline.py deleted file mode 100644 index 41a73588c3f..00000000000 --- a/tests/test_catmull_rom_spline.py +++ /dev/null @@ -1,16 +0,0 @@ -import conftest -from PathPlanning.Catmull_RomSplinePath.catmull_rom_spline_path import catmull_rom_spline - -def test_catmull_rom_spline(): - way_points = [[0, 0], [1, 2], [2, 0], [3, 3]] - num_points = 100 - - spline_x, spline_y = catmull_rom_spline(way_points, num_points) - - assert spline_x.size > 0, "Spline X coordinates should not be empty" - assert spline_y.size > 0, "Spline Y coordinates should not be empty" - - assert spline_x.shape == spline_y.shape, "Spline X and Y coordinates should have the same shape" - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_cgmres_nmpc.py b/tests/test_cgmres_nmpc.py deleted file mode 100644 index db3ada5065c..00000000000 --- a/tests/test_cgmres_nmpc.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathTracking.cgmres_nmpc import cgmres_nmpc as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_circle_fitting.py b/tests/test_circle_fitting.py deleted file mode 100644 index b3888d7cc31..00000000000 --- a/tests/test_circle_fitting.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from Mapping.circle_fitting import circle_fitting as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_closed_loop_rrt_star_car.py b/tests/test_closed_loop_rrt_star_car.py deleted file mode 100644 index c33e413e926..00000000000 --- a/tests/test_closed_loop_rrt_star_car.py +++ /dev/null @@ -1,13 +0,0 @@ -import conftest -from PathPlanning.ClosedLoopRRTStar import closed_loop_rrt_star_car as m -import random - - -def test_1(): - random.seed(12345) - m.show_animation = False - m.main(gx=1.0, gy=0.0, gyaw=0.0, max_iter=5) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_clothoidal_paths.py b/tests/test_clothoidal_paths.py deleted file mode 100644 index 0b038c03381..00000000000 --- a/tests/test_clothoidal_paths.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.ClothoidPath import clothoid_path_planner as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_codestyle.py b/tests/test_codestyle.py deleted file mode 100644 index 55e558c184e..00000000000 --- a/tests/test_codestyle.py +++ /dev/null @@ -1,138 +0,0 @@ -""" -Diff code style checker with ruff - -This code come from: -https://github.com/scipy/scipy/blob/main/tools/lint.py - -Scipy's licence: https://github.com/scipy/scipy/blob/main/LICENSE.txt -Copyright (c) 2001-2002 Enthought, Inc. 2003-2022, SciPy Developers. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" -import conftest -import os -import subprocess - - -CONFIG = os.path.join( - os.path.abspath(os.path.dirname(os.path.dirname(__file__))), - 'ruff.toml', -) - -ROOT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) - - -def run_ruff(files, fix): - if not files: - return 0, "" - args = ['--fix'] if fix else [] - res = subprocess.run( - ['ruff', 'check', f'--config={CONFIG}'] + args + files, - stdout=subprocess.PIPE, - encoding='utf-8' - ) - return res.returncode, res.stdout - - -def rev_list(branch, num_commits): - """List commits in reverse chronological order. - Only the first `num_commits` are shown. - """ - res = subprocess.run( - [ - 'git', - 'rev-list', - '--max-count', - f'{num_commits}', - '--first-parent', - branch - ], - stdout=subprocess.PIPE, - encoding='utf-8', - ) - res.check_returncode() - return res.stdout.rstrip('\n').split('\n') - - -def find_branch_point(branch): - """Find when the current branch split off from the given branch. - It is based off of this Stackoverflow post: - https://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git#4991675 - """ - branch_commits = rev_list('HEAD', 1000) - main_commits = set(rev_list(branch, 1000)) - for branch_commit in branch_commits: - if branch_commit in main_commits: - return branch_commit - - # If a branch split off over 1000 commits ago we will fail to find - # the ancestor. - raise RuntimeError( - 'Failed to find a common ancestor in the last 1000 commits') - - -def find_diff(sha): - """Find the diff since the given sha.""" - files = ['*.py'] - res = subprocess.run( - ['git', 'diff', '--unified=0', sha, '--'] + files, - stdout=subprocess.PIPE, - encoding='utf-8' - ) - res.check_returncode() - return res.stdout - - -def diff_files(sha): - """Find the diff since the given SHA.""" - res = subprocess.run( - ['git', 'diff', '--name-only', '--diff-filter=ACMR', '-z', sha, '--', - '*.py', '*.pyx', '*.pxd', '*.pxi'], - stdout=subprocess.PIPE, - encoding='utf-8' - ) - res.check_returncode() - return [os.path.join(ROOT_DIR, f) for f in res.stdout.split('\0') if f] - - -def test(): - branch_commit = find_branch_point("origin/master") - files = diff_files(branch_commit) - print(files) - rc, errors = run_ruff(files, fix=True) - if errors: - print(errors) - else: - print("No lint errors found.") - assert rc == 0 - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_cubature_kalman_filter.py b/tests/test_cubature_kalman_filter.py deleted file mode 100644 index 00f9d8bc5ff..00000000000 --- a/tests/test_cubature_kalman_filter.py +++ /dev/null @@ -1,13 +0,0 @@ -import conftest -from Localization.cubature_kalman_filter import cubature_kalman_filter as m - - -def test1(): - m.show_final = False - m.show_animation = False - m.show_ellipse = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_d_star_lite.py b/tests/test_d_star_lite.py deleted file mode 100644 index b60a140a89b..00000000000 --- a/tests/test_d_star_lite.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.DStarLite import d_star_lite as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_depth_first_search.py b/tests/test_depth_first_search.py deleted file mode 100644 index 8dd009278f1..00000000000 --- a/tests/test_depth_first_search.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.DepthFirstSearch import depth_first_search as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_dijkstra.py b/tests/test_dijkstra.py deleted file mode 100644 index 40404153d8b..00000000000 --- a/tests/test_dijkstra.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.Dijkstra import dijkstra as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_distance_map.py b/tests/test_distance_map.py deleted file mode 100644 index df6e394e2ce..00000000000 --- a/tests/test_distance_map.py +++ /dev/null @@ -1,118 +0,0 @@ -import conftest # noqa -import numpy as np -from Mapping.DistanceMap import distance_map as m - - -def test_compute_sdf(): - """Test the computation of Signed Distance Field (SDF)""" - # Create a simple obstacle map for testing - obstacles = np.array([[0, 0, 0], [0, 1, 0], [0, 0, 0]]) - - sdf = m.compute_sdf(obstacles) - - # Verify basic properties of SDF - assert sdf.shape == obstacles.shape, "SDF should have the same shape as input map" - assert np.all(np.isfinite(sdf)), "SDF should not contain infinite values" - - # Verify SDF value is negative at obstacle position - assert sdf[1, 1] < 0, "SDF value should be negative at obstacle position" - - # Verify SDF value is positive in free space - assert sdf[0, 0] > 0, "SDF value should be positive in free space" - - -def test_compute_udf(): - """Test the computation of Unsigned Distance Field (UDF)""" - # Create obstacle map for testing - obstacles = np.array([[0, 0, 0], [0, 1, 0], [0, 0, 0]]) - - udf = m.compute_udf(obstacles) - - # Verify basic properties of UDF - assert udf.shape == obstacles.shape, "UDF should have the same shape as input map" - assert np.all(np.isfinite(udf)), "UDF should not contain infinite values" - assert np.all(udf >= 0), "All UDF values should be non-negative" - - # Verify UDF value is 0 at obstacle position - assert np.abs(udf[1, 1]) < 1e-10, "UDF value should be 0 at obstacle position" - - # Verify UDF value is 1 for adjacent cells - assert np.abs(udf[0, 1] - 1.0) < 1e-10, ( - "UDF value should be 1 for cells adjacent to obstacle" - ) - assert np.abs(udf[1, 0] - 1.0) < 1e-10, ( - "UDF value should be 1 for cells adjacent to obstacle" - ) - assert np.abs(udf[1, 2] - 1.0) < 1e-10, ( - "UDF value should be 1 for cells adjacent to obstacle" - ) - assert np.abs(udf[2, 1] - 1.0) < 1e-10, ( - "UDF value should be 1 for cells adjacent to obstacle" - ) - - -def test_dt(): - """Test the computation of 1D distance transform""" - # Create test data - d = np.array([m.INF, 0, m.INF]) - m.dt(d) - - # Verify distance transform results - assert np.all(np.isfinite(d)), ( - "Distance transform result should not contain infinite values" - ) - assert d[1] == 0, "Distance at obstacle position should be 0" - assert d[0] == 1, "Distance at adjacent position should be 1" - assert d[2] == 1, "Distance at adjacent position should be 1" - - -def test_compute_sdf_empty(): - """Test SDF computation with empty map""" - # Test with empty map (no obstacles) - empty_map = np.zeros((5, 5)) - sdf = m.compute_sdf(empty_map) - - assert np.all(sdf > 0), "All SDF values should be positive for empty map" - assert sdf.shape == empty_map.shape, "Output shape should match input shape" - - -def test_compute_sdf_full(): - """Test SDF computation with fully occupied map""" - # Test with fully occupied map - full_map = np.ones((5, 5)) - sdf = m.compute_sdf(full_map) - - assert np.all(sdf < 0), "All SDF values should be negative for fully occupied map" - assert sdf.shape == full_map.shape, "Output shape should match input shape" - - -def test_compute_udf_invalid_input(): - """Test UDF computation with invalid input values""" - # Test with invalid values (not 0 or 1) - invalid_map = np.array([[0, 2, 0], [0, -1, 0], [0, 0.5, 0]]) - - try: - m.compute_udf(invalid_map) - assert False, "Should raise ValueError for invalid input values" - except ValueError: - pass - - -def test_compute_udf_empty(): - """Test UDF computation with empty map""" - # Test with empty map - empty_map = np.zeros((5, 5)) - udf = m.compute_udf(empty_map) - - assert np.all(udf > 0), "All UDF values should be positive for empty map" - assert np.all(np.isfinite(udf)), "UDF should not contain infinite values" - - -def test_main(): - """Test the execution of main function""" - m.ENABLE_PLOT = False - m.main() - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_drone_3d_trajectory_following.py b/tests/test_drone_3d_trajectory_following.py deleted file mode 100644 index e3fd4170247..00000000000 --- a/tests/test_drone_3d_trajectory_following.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest -from AerialNavigation.drone_3d_trajectory_following \ - import drone_3d_trajectory_following as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_dstar.py b/tests/test_dstar.py deleted file mode 100644 index f8f40fecefc..00000000000 --- a/tests/test_dstar.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.DStar import dstar as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_dubins_path_planning.py b/tests/test_dubins_path_planning.py deleted file mode 100644 index aceb0b752a2..00000000000 --- a/tests/test_dubins_path_planning.py +++ /dev/null @@ -1,92 +0,0 @@ -import numpy as np - -import conftest -from PathPlanning.DubinsPath import dubins_path_planner - -np.random.seed(12345) - - -def check_edge_condition(px, py, pyaw, start_x, start_y, start_yaw, end_x, - end_y, end_yaw): - assert (abs(px[0] - start_x) <= 0.01) - assert (abs(py[0] - start_y) <= 0.01) - assert (abs(pyaw[0] - start_yaw) <= 0.01) - assert (abs(px[-1] - end_x) <= 0.01) - assert (abs(py[-1] - end_y) <= 0.01) - assert (abs(pyaw[-1] - end_yaw) <= 0.01) - - -def check_path_length(px, py, lengths): - path_len = sum( - [np.hypot(dx, dy) for (dx, dy) in zip(np.diff(px), np.diff(py))]) - assert (abs(path_len - sum(lengths)) <= 0.1) - - -def test_1(): - start_x = 1.0 # [m] - start_y = 1.0 # [m] - start_yaw = np.deg2rad(45.0) # [rad] - - end_x = -3.0 # [m] - end_y = -3.0 # [m] - end_yaw = np.deg2rad(-45.0) # [rad] - - curvature = 1.0 - - px, py, pyaw, mode, lengths = dubins_path_planner.plan_dubins_path( - start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature) - - check_edge_condition(px, py, pyaw, start_x, start_y, start_yaw, end_x, - end_y, end_yaw) - check_path_length(px, py, lengths) - - -def test_2(): - dubins_path_planner.show_animation = False - dubins_path_planner.main() - - -def test_3(): - N_TEST = 10 - - for i in range(N_TEST): - start_x = (np.random.rand() - 0.5) * 10.0 # [m] - start_y = (np.random.rand() - 0.5) * 10.0 # [m] - start_yaw = np.deg2rad((np.random.rand() - 0.5) * 180.0) # [rad] - - end_x = (np.random.rand() - 0.5) * 10.0 # [m] - end_y = (np.random.rand() - 0.5) * 10.0 # [m] - end_yaw = np.deg2rad((np.random.rand() - 0.5) * 180.0) # [rad] - - curvature = 1.0 / (np.random.rand() * 5.0) - - px, py, pyaw, mode, lengths = \ - dubins_path_planner.plan_dubins_path( - start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature) - - check_edge_condition(px, py, pyaw, start_x, start_y, start_yaw, end_x, - end_y, end_yaw) - check_path_length(px, py, lengths) - - -def test_path_plannings_types(): - dubins_path_planner.show_animation = False - start_x = 1.0 # [m] - start_y = 1.0 # [m] - start_yaw = np.deg2rad(45.0) # [rad] - - end_x = -3.0 # [m] - end_y = -3.0 # [m] - end_yaw = np.deg2rad(-45.0) # [rad] - - curvature = 1.0 - - _, _, _, mode, _ = dubins_path_planner.plan_dubins_path( - start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature, - selected_types=["RSL"]) - - assert mode == ["R", "S", "L"] - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_dynamic_movement_primitives.py b/tests/test_dynamic_movement_primitives.py deleted file mode 100644 index 3ab1c8a32c5..00000000000 --- a/tests/test_dynamic_movement_primitives.py +++ /dev/null @@ -1,49 +0,0 @@ -import conftest -import numpy as np -from PathPlanning.DynamicMovementPrimitives import \ - dynamic_movement_primitives - - -def test_1(): - # test that trajectory can be learned from user-passed data - T = 5 - t = np.arange(0, T, 0.01) - sin_t = np.sin(t) - train_data = np.array([t, sin_t]).T - - DMP_controller = dynamic_movement_primitives.DMP(train_data, T) - DMP_controller.recreate_trajectory(train_data[0], train_data[-1], 4) - - -def test_2(): - # test that length of trajectory is equal to desired number of timesteps - T = 5 - t = np.arange(0, T, 0.01) - sin_t = np.sin(t) - train_data = np.array([t, sin_t]).T - - DMP_controller = dynamic_movement_primitives.DMP(train_data, T) - t, path = DMP_controller.recreate_trajectory(train_data[0], - train_data[-1], 4) - - assert(path.shape[0] == DMP_controller.timesteps) - - -def test_3(): - # check that learned trajectory is close to initial - T = 3*np.pi/2 - A_noise = 0.02 - t = np.arange(0, T, 0.01) - noisy_sin_t = np.sin(t) + A_noise*np.random.rand(len(t)) - train_data = np.array([t, noisy_sin_t]).T - - DMP_controller = dynamic_movement_primitives.DMP(train_data, T) - t, pos = DMP_controller.recreate_trajectory(train_data[0], - train_data[-1], T) - - diff = abs(pos[:, 1] - noisy_sin_t) - assert(max(diff) < 5*A_noise) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_dynamic_window_approach.py b/tests/test_dynamic_window_approach.py deleted file mode 100644 index fdb452b4a7a..00000000000 --- a/tests/test_dynamic_window_approach.py +++ /dev/null @@ -1,48 +0,0 @@ -import conftest -import numpy as np - -from PathPlanning.DynamicWindowApproach import dynamic_window_approach as m - - -def test_main1(): - m.show_animation = False - m.main(gx=1.0, gy=1.0) - - -def test_main2(): - m.show_animation = False - m.main(gx=1.0, gy=1.0, robot_type=m.RobotType.rectangle) - - -def test_stuck_main(): - m.show_animation = False - # adjust cost - m.config.to_goal_cost_gain = 0.2 - m.config.obstacle_cost_gain = 2.0 - # obstacles and goals for stuck condition - m.config.ob = -1 * np.array([[-1.0, -1.0], - [0.0, 2.0], - [2.0, 6.0], - [2.0, 8.0], - [3.0, 9.27], - [3.79, 9.39], - [7.25, 8.97], - [7.0, 2.0], - [3.0, 4.0], - [6.0, 5.0], - [3.5, 5.8], - [6.0, 9.0], - [8.8, 9.0], - [5.0, 9.0], - [7.5, 3.0], - [9.0, 8.0], - [5.8, 4.4], - [12.0, 12.0], - [3.0, 2.0], - [13.0, 13.0] - ]) - m.main(gx=-5.0, gy=-7.0) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_ekf_slam.py b/tests/test_ekf_slam.py deleted file mode 100644 index 4181bb64bae..00000000000 --- a/tests/test_ekf_slam.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from SLAM.EKFSLAM import ekf_slam as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_elastic_bands.py b/tests/test_elastic_bands.py deleted file mode 100644 index ad4e13af1af..00000000000 --- a/tests/test_elastic_bands.py +++ /dev/null @@ -1,23 +0,0 @@ -import conftest -import numpy as np -from PathPlanning.ElasticBands.elastic_bands import ElasticBands - - -def test_1(): - path = np.load("PathPlanning/ElasticBands/path.npy") - obstacles_points = np.load("PathPlanning/ElasticBands/obstacles.npy") - obstacles = np.zeros((500, 500)) - for x, y in obstacles_points: - size = 30 # Side length of the square - half_size = size // 2 - x_start = max(0, x - half_size) - x_end = min(obstacles.shape[0], x + half_size) - y_start = max(0, y - half_size) - y_end = min(obstacles.shape[1], y + half_size) - obstacles[x_start:x_end, y_start:y_end] = 1 - elastic_bands = ElasticBands(path, obstacles) - elastic_bands.update_bubbles() - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_eta3_spline_path.py b/tests/test_eta3_spline_path.py deleted file mode 100644 index 7fa3883ea59..00000000000 --- a/tests/test_eta3_spline_path.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.Eta3SplinePath import eta3_spline_path as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_extended_kalman_filter.py b/tests/test_extended_kalman_filter.py deleted file mode 100644 index d9ad6437a8e..00000000000 --- a/tests/test_extended_kalman_filter.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from Localization.extended_kalman_filter import extended_kalman_filter as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_fast_slam1.py b/tests/test_fast_slam1.py deleted file mode 100644 index b72ab6b9efa..00000000000 --- a/tests/test_fast_slam1.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest -from SLAM.FastSLAM1 import fast_slam1 as m - - -def test1(): - m.show_animation = False - m.SIM_TIME = 3.0 - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_fast_slam2.py b/tests/test_fast_slam2.py deleted file mode 100644 index 95cdc69d424..00000000000 --- a/tests/test_fast_slam2.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest -from SLAM.FastSLAM2 import fast_slam2 as m - - -def test1(): - m.show_animation = False - m.SIM_TIME = 3.0 - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_flow_field.py b/tests/test_flow_field.py deleted file mode 100644 index d049731fe59..00000000000 --- a/tests/test_flow_field.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -import PathPlanning.FlowField.flowfield as flow_field - - -def test(): - flow_field.show_animation = False - flow_field.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_frenet_optimal_trajectory.py b/tests/test_frenet_optimal_trajectory.py deleted file mode 100644 index b8761ff4a6c..00000000000 --- a/tests/test_frenet_optimal_trajectory.py +++ /dev/null @@ -1,48 +0,0 @@ -import conftest -from PathPlanning.FrenetOptimalTrajectory import frenet_optimal_trajectory as m -from PathPlanning.FrenetOptimalTrajectory.frenet_optimal_trajectory import ( - LateralMovement, - LongitudinalMovement, -) - - -def default_scenario_test(): - m.show_animation = False - m.SIM_LOOP = 5 - m.main() - - -def high_speed_and_merging_and_stopping_scenario_test(): - m.show_animation = False - m.LATERAL_MOVEMENT = LateralMovement.HIGH_SPEED - m.LONGITUDINAL_MOVEMENT = LongitudinalMovement.MERGING_AND_STOPPING - m.SIM_LOOP = 5 - m.main() - - -def high_speed_and_velocity_keeping_scenario_test(): - m.show_animation = False - m.LATERAL_MOVEMENT = LateralMovement.HIGH_SPEED - m.LONGITUDINAL_MOVEMENT = LongitudinalMovement.VELOCITY_KEEPING - m.SIM_LOOP = 5 - m.main() - - -def low_speed_and_velocity_keeping_scenario_test(): - m.show_animation = False - m.LATERAL_MOVEMENT = LateralMovement.LOW_SPEED - m.LONGITUDINAL_MOVEMENT = LongitudinalMovement.VELOCITY_KEEPING - m.SIM_LOOP = 5 - m.main() - - -def low_speed_and_merging_and_stopping_scenario_test(): - m.show_animation = False - m.LATERAL_MOVEMENT = LateralMovement.LOW_SPEED - m.LONGITUDINAL_MOVEMENT = LongitudinalMovement.MERGING_AND_STOPPING - m.SIM_LOOP = 5 - m.main() - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_gaussian_grid_map.py b/tests/test_gaussian_grid_map.py deleted file mode 100644 index af1e138721b..00000000000 --- a/tests/test_gaussian_grid_map.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from Mapping.gaussian_grid_map import gaussian_grid_map as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_graph_based_slam.py b/tests/test_graph_based_slam.py deleted file mode 100644 index 67d75f0f858..00000000000 --- a/tests/test_graph_based_slam.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest -from SLAM.GraphBasedSLAM import graph_based_slam as m - - -def test_1(): - m.show_animation = False - m.SIM_TIME = 20.0 - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_greedy_best_first_search.py b/tests/test_greedy_best_first_search.py deleted file mode 100644 index e573ecf6255..00000000000 --- a/tests/test_greedy_best_first_search.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.GreedyBestFirstSearch import greedy_best_first_search as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_grid_based_sweep_coverage_path_planner.py b/tests/test_grid_based_sweep_coverage_path_planner.py deleted file mode 100644 index 8cbe36eb497..00000000000 --- a/tests/test_grid_based_sweep_coverage_path_planner.py +++ /dev/null @@ -1,118 +0,0 @@ -import conftest -from PathPlanning.GridBasedSweepCPP \ - import grid_based_sweep_coverage_path_planner - -grid_based_sweep_coverage_path_planner.do_animation = False -RIGHT = grid_based_sweep_coverage_path_planner. \ - SweepSearcher.MovingDirection.RIGHT -LEFT = grid_based_sweep_coverage_path_planner. \ - SweepSearcher.MovingDirection.LEFT -UP = grid_based_sweep_coverage_path_planner. \ - SweepSearcher.SweepDirection.UP -DOWN = grid_based_sweep_coverage_path_planner. \ - SweepSearcher.SweepDirection.DOWN - - -def test_planning1(): - ox = [0.0, 20.0, 50.0, 100.0, 130.0, 40.0, 0.0] - oy = [0.0, -20.0, 0.0, 30.0, 60.0, 80.0, 0.0] - resolution = 5.0 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=LEFT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=UP, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=UP, - ) - assert len(px) >= 5 - - -def test_planning2(): - ox = [0.0, 50.0, 50.0, 0.0, 0.0] - oy = [0.0, 0.0, 30.0, 30.0, 0.0] - resolution = 1.3 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=LEFT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=UP, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - -def test_planning3(): - ox = [0.0, 20.0, 50.0, 200.0, 130.0, 40.0, 0.0] - oy = [0.0, -80.0, 0.0, 30.0, 60.0, 80.0, 0.0] - resolution = 5.1 - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=LEFT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=UP, - ) - assert len(px) >= 5 - - px, py = grid_based_sweep_coverage_path_planner.planning( - ox, oy, resolution, - moving_direction=RIGHT, - sweeping_direction=DOWN, - ) - assert len(px) >= 5 - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_grid_map_lib.py b/tests/test_grid_map_lib.py deleted file mode 100644 index 670b357ad3f..00000000000 --- a/tests/test_grid_map_lib.py +++ /dev/null @@ -1,40 +0,0 @@ -from Mapping.grid_map_lib.grid_map_lib import GridMap -import conftest -import numpy as np - - -def test_position_set(): - grid_map = GridMap(100, 120, 0.5, 10.0, -0.5) - - grid_map.set_value_from_xy_pos(10.1, -1.1, 1.0) - grid_map.set_value_from_xy_pos(10.1, -0.1, 1.0) - grid_map.set_value_from_xy_pos(10.1, 1.1, 1.0) - grid_map.set_value_from_xy_pos(11.1, 0.1, 1.0) - grid_map.set_value_from_xy_pos(10.1, 0.1, 1.0) - grid_map.set_value_from_xy_pos(9.1, 0.1, 1.0) - - -def test_polygon_set(): - ox = [0.0, 4.35, 20.0, 50.0, 100.0, 130.0, 40.0] - oy = [0.0, -4.15, -20.0, 0.0, 30.0, 60.0, 80.0] - - grid_map = GridMap(600, 290, 0.7, 60.0, 30.5) - - grid_map.set_value_from_polygon(ox, oy, 1.0, inside=False) - grid_map.set_value_from_polygon(np.array(ox), np.array(oy), - 1.0, inside=False) - - -def test_xy_and_grid_index_conversion(): - grid_map = GridMap(100, 120, 0.5, 10.0, -0.5) - - for x_ind in range(grid_map.width): - for y_ind in range(grid_map.height): - grid_ind = grid_map.calc_grid_index_from_xy_index(x_ind, y_ind) - x_ind_2, y_ind_2 = grid_map.calc_xy_index_from_grid_index(grid_ind) - assert x_ind == x_ind_2 - assert y_ind == y_ind_2 - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_histogram_filter.py b/tests/test_histogram_filter.py deleted file mode 100644 index 4474ead0979..00000000000 --- a/tests/test_histogram_filter.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest -from Localization.histogram_filter import histogram_filter as m - - -def test1(): - m.show_animation = False - m.SIM_TIME = 1.0 - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_hybrid_a_star.py b/tests/test_hybrid_a_star.py deleted file mode 100644 index dbcf3ba9f43..00000000000 --- a/tests/test_hybrid_a_star.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.HybridAStar import hybrid_a_star as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_informed_rrt_star.py b/tests/test_informed_rrt_star.py deleted file mode 100644 index 10974ecfcb5..00000000000 --- a/tests/test_informed_rrt_star.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from PathPlanning.InformedRRTStar import informed_rrt_star as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_inverted_pendulum_lqr_control.py b/tests/test_inverted_pendulum_lqr_control.py deleted file mode 100644 index 62afda71c38..00000000000 --- a/tests/test_inverted_pendulum_lqr_control.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from InvertedPendulum import inverted_pendulum_lqr_control as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_inverted_pendulum_mpc_control.py b/tests/test_inverted_pendulum_mpc_control.py deleted file mode 100644 index 94859c2e0af..00000000000 --- a/tests/test_inverted_pendulum_mpc_control.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest - -from InvertedPendulum import inverted_pendulum_mpc_control as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_iterative_closest_point.py b/tests/test_iterative_closest_point.py deleted file mode 100644 index 3e726b5649a..00000000000 --- a/tests/test_iterative_closest_point.py +++ /dev/null @@ -1,16 +0,0 @@ -import conftest -from SLAM.iterative_closest_point import iterative_closest_point as m - - -def test_1(): - m.show_animation = False - m.main() - - -def test_2(): - m.show_animation = False - m.main_3d_points() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_kmeans_clustering.py b/tests/test_kmeans_clustering.py deleted file mode 100644 index 5e39d64ae6e..00000000000 --- a/tests/test_kmeans_clustering.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest -from Mapping.kmeans_clustering import kmeans_clustering as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_lqr_rrt_star.py b/tests/test_lqr_rrt_star.py deleted file mode 100644 index 444b4616b85..00000000000 --- a/tests/test_lqr_rrt_star.py +++ /dev/null @@ -1,14 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.LQRRRTStar import lqr_rrt_star as m -import random - -random.seed(12345) - - -def test1(): - m.show_animation = False - m.main(maxIter=5) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_lqr_speed_steer_control.py b/tests/test_lqr_speed_steer_control.py deleted file mode 100644 index cee9759a26b..00000000000 --- a/tests/test_lqr_speed_steer_control.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathTracking.lqr_speed_steer_control import lqr_speed_steer_control as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_lqr_steer_control.py b/tests/test_lqr_steer_control.py deleted file mode 100644 index 24427a8ffdd..00000000000 --- a/tests/test_lqr_steer_control.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathTracking.lqr_steer_control import lqr_steer_control as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_model_predictive_speed_and_steer_control.py b/tests/test_model_predictive_speed_and_steer_control.py deleted file mode 100644 index 9bc8ccf31ce..00000000000 --- a/tests/test_model_predictive_speed_and_steer_control.py +++ /dev/null @@ -1,18 +0,0 @@ -import conftest # Add root path to sys.path - -from PathTracking.model_predictive_speed_and_steer_control \ - import model_predictive_speed_and_steer_control as m - - -def test_1(): - m.show_animation = False - m.main() - - -def test_2(): - m.show_animation = False - m.main2() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_move_to_pose.py b/tests/test_move_to_pose.py deleted file mode 100644 index e06d801555b..00000000000 --- a/tests/test_move_to_pose.py +++ /dev/null @@ -1,90 +0,0 @@ -import itertools -import numpy as np -import conftest # Add root path to sys.path -from PathTracking.move_to_pose import move_to_pose as m - - -def test_random(): - m.show_animation = False - m.main() - - -def test_stability(): - """ - This unit test tests the move_to_pose.py program for stability - """ - m.show_animation = False - x_start = 5 - y_start = 5 - theta_start = 0 - x_goal = 1 - y_goal = 4 - theta_goal = 0 - _, _, v_traj, w_traj = m.move_to_pose( - x_start, y_start, theta_start, x_goal, y_goal, theta_goal - ) - - def v_is_change(current, previous): - return abs(current - previous) > m.MAX_LINEAR_SPEED - - def w_is_change(current, previous): - return abs(current - previous) > m.MAX_ANGULAR_SPEED - - # Check if the speed is changing too much - window_size = 10 - count_threshold = 4 - v_change = [v_is_change(v_traj[i], v_traj[i - 1]) for i in range(1, len(v_traj))] - w_change = [w_is_change(w_traj[i], w_traj[i - 1]) for i in range(1, len(w_traj))] - for i in range(len(v_change) - window_size + 1): - v_window = v_change[i : i + window_size] - w_window = w_change[i : i + window_size] - - v_unstable = sum(v_window) > count_threshold - w_unstable = sum(w_window) > count_threshold - - assert not v_unstable, ( - f"v_unstable in window [{i}, {i + window_size}], unstable count: {sum(v_window)}" - ) - assert not w_unstable, ( - f"w_unstable in window [{i}, {i + window_size}], unstable count: {sum(w_window)}" - ) - - -def test_reach_goal(): - """ - This unit test tests the move_to_pose.py program for reaching the goal - """ - m.show_animation = False - x_start = 5 - y_start = 5 - theta_start_list = [0, np.pi / 2, np.pi, 3 * np.pi / 2] - x_goal_list = [0, 5, 10] - y_goal_list = [0, 5, 10] - theta_goal = 0 - for theta_start, x_goal, y_goal in itertools.product( - theta_start_list, x_goal_list, y_goal_list - ): - x_traj, y_traj, _, _ = m.move_to_pose( - x_start, y_start, theta_start, x_goal, y_goal, theta_goal - ) - x_diff = x_goal - x_traj[-1] - y_diff = y_goal - y_traj[-1] - rho = np.hypot(x_diff, y_diff) - assert rho < 0.001, ( - f"start:[{x_start}, {y_start}, {theta_start}], goal:[{x_goal}, {y_goal}, {theta_goal}], rho: {rho} is too large" - ) - - -def test_max_speed(): - """ - This unit test tests the move_to_pose.py program for a MAX_LINEAR_SPEED and - MAX_ANGULAR_SPEED - """ - m.show_animation = False - m.MAX_LINEAR_SPEED = 11 - m.MAX_ANGULAR_SPEED = 5 - m.main() - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_move_to_pose_robot.py b/tests/test_move_to_pose_robot.py deleted file mode 100644 index 7a82f985561..00000000000 --- a/tests/test_move_to_pose_robot.py +++ /dev/null @@ -1,14 +0,0 @@ -import conftest # Add root path to sys.path -from PathTracking.move_to_pose import move_to_pose as m - - -def test_1(): - """ - This unit test tests the move_to_pose_robot.py program - """ - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_mypy_type_check.py b/tests/test_mypy_type_check.py deleted file mode 100644 index 6b933c1011a..00000000000 --- a/tests/test_mypy_type_check.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -import subprocess - -import conftest - -SUBPACKAGE_LIST = [ - "AerialNavigation", - "ArmNavigation", - "Bipedal", - "Localization", - "Mapping", - "PathPlanning", - "PathTracking", - "SLAM", - "InvertedPendulum" -] - - -def run_mypy(dir_name, project_path, config_path): - res = subprocess.run( - ['mypy', - '--config-file', - config_path, - '-p', - dir_name], - cwd=project_path, - stdout=subprocess.PIPE, - encoding='utf-8') - return res.returncode, res.stdout - - -def test(): - project_dir_path = os.path.dirname( - os.path.dirname(os.path.abspath(__file__))) - print(f"{project_dir_path=}") - - config_path = os.path.join(project_dir_path, "mypy.ini") - print(f"{config_path=}") - - for sub_package_name in SUBPACKAGE_LIST: - rc, errors = run_mypy(sub_package_name, project_dir_path, config_path) - if errors: - print(errors) - else: - print("No lint errors found.") - assert rc == 0 - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_n_joint_arm_to_point_control.py b/tests/test_n_joint_arm_to_point_control.py deleted file mode 100644 index 1d886d36705..00000000000 --- a/tests/test_n_joint_arm_to_point_control.py +++ /dev/null @@ -1,15 +0,0 @@ -import conftest # Add root path to sys.path -from ArmNavigation.n_joint_arm_to_point_control\ - import n_joint_arm_to_point_control as m -import random - -random.seed(12345) - - -def test1(): - m.show_animation = False - m.animation() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_normal_vector_estimation.py b/tests/test_normal_vector_estimation.py deleted file mode 100644 index 7612f22aa73..00000000000 --- a/tests/test_normal_vector_estimation.py +++ /dev/null @@ -1,19 +0,0 @@ -import conftest # Add root path to sys.path -from Mapping.normal_vector_estimation import normal_vector_estimation as m -import random - -random.seed(12345) - - -def test_1(): - m.show_animation = False - m.main1() - - -def test_2(): - m.show_animation = False - m.main2() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_particle_filter.py b/tests/test_particle_filter.py deleted file mode 100644 index 13a20f602af..00000000000 --- a/tests/test_particle_filter.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from Localization.particle_filter import particle_filter as m - - -def test_1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_point_cloud_sampling.py b/tests/test_point_cloud_sampling.py deleted file mode 100644 index 8f6447c69c4..00000000000 --- a/tests/test_point_cloud_sampling.py +++ /dev/null @@ -1,15 +0,0 @@ -import conftest # Add root path to sys.path -from Mapping.point_cloud_sampling import point_cloud_sampling as m - - -def test_1(capsys): - m.do_plot = False - m.main() - captured = capsys.readouterr() - assert "voxel_sampling_points.shape=(27, 3)" in captured.out - assert "farthest_sampling_points.shape=(20, 3)" in captured.out - assert "poisson_disk_points.shape=(20, 3)" in captured.out - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_potential_field_planning.py b/tests/test_potential_field_planning.py deleted file mode 100644 index ce178d793d2..00000000000 --- a/tests/test_potential_field_planning.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.PotentialFieldPlanning import potential_field_planning as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_probabilistic_road_map.py b/tests/test_probabilistic_road_map.py deleted file mode 100644 index 6c5eb540b1c..00000000000 --- a/tests/test_probabilistic_road_map.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest # Add root path to sys.path -import numpy as np -from PathPlanning.ProbabilisticRoadMap import probabilistic_road_map - - -def test1(): - probabilistic_road_map.show_animation = False - probabilistic_road_map.main(rng=np.random.default_rng(1233)) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_pure_pursuit.py b/tests/test_pure_pursuit.py deleted file mode 100644 index 0e0b83bf6ce..00000000000 --- a/tests/test_pure_pursuit.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathTracking.pure_pursuit import pure_pursuit as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_quintic_polynomials_planner.py b/tests/test_quintic_polynomials_planner.py deleted file mode 100644 index 43f3c6bada2..00000000000 --- a/tests/test_quintic_polynomials_planner.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.QuinticPolynomialsPlanner import quintic_polynomials_planner as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_raycasting_grid_map.py b/tests/test_raycasting_grid_map.py deleted file mode 100644 index f08ae9277e3..00000000000 --- a/tests/test_raycasting_grid_map.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from Mapping.raycasting_grid_map import raycasting_grid_map as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rear_wheel_feedback.py b/tests/test_rear_wheel_feedback.py deleted file mode 100644 index 895eb188b32..00000000000 --- a/tests/test_rear_wheel_feedback.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathTracking.rear_wheel_feedback import rear_wheel_feedback as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rectangle_fitting.py b/tests/test_rectangle_fitting.py deleted file mode 100644 index cb28b6035ec..00000000000 --- a/tests/test_rectangle_fitting.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from Mapping.rectangle_fitting import rectangle_fitting as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_reeds_shepp_path_planning.py b/tests/test_reeds_shepp_path_planning.py deleted file mode 100644 index 34ccfe7730c..00000000000 --- a/tests/test_reeds_shepp_path_planning.py +++ /dev/null @@ -1,57 +0,0 @@ -import numpy as np - -import conftest # Add root path to sys.path -from PathPlanning.ReedsSheppPath import reeds_shepp_path_planning as m - - -def check_edge_condition(px, py, pyaw, start_x, start_y, start_yaw, end_x, - end_y, end_yaw): - assert (abs(px[0] - start_x) <= 0.01) - assert (abs(py[0] - start_y) <= 0.01) - assert (abs(pyaw[0] - start_yaw) <= 0.01) - assert (abs(px[-1] - end_x) <= 0.01) - assert (abs(py[-1] - end_y) <= 0.01) - assert (abs(pyaw[-1] - end_yaw) <= 0.01) - - -def check_path_length(px, py, lengths): - sum_len = sum(abs(length) for length in lengths) - dpx = np.diff(px) - dpy = np.diff(py) - actual_len = sum( - np.hypot(dx, dy) for (dx, dy) in zip(dpx, dpy)) - diff_len = sum_len - actual_len - assert (diff_len <= 0.01) - - -def test1(): - m.show_animation = False - m.main() - - -def test2(): - N_TEST = 10 - np.random.seed(1234) - - for i in range(N_TEST): - start_x = (np.random.rand() - 0.5) * 10.0 # [m] - start_y = (np.random.rand() - 0.5) * 10.0 # [m] - start_yaw = np.deg2rad((np.random.rand() - 0.5) * 180.0) # [rad] - - end_x = (np.random.rand() - 0.5) * 10.0 # [m] - end_y = (np.random.rand() - 0.5) * 10.0 # [m] - end_yaw = np.deg2rad((np.random.rand() - 0.5) * 180.0) # [rad] - - curvature = 1.0 / (np.random.rand() * 5.0) - - px, py, pyaw, mode, lengths = m.reeds_shepp_path_planning( - start_x, start_y, start_yaw, - end_x, end_y, end_yaw, curvature) - - check_edge_condition(px, py, pyaw, start_x, start_y, start_yaw, end_x, - end_y, end_yaw) - check_path_length(px, py, lengths) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rocket_powered_landing.py b/tests/test_rocket_powered_landing.py deleted file mode 100644 index 2f294c74cff..00000000000 --- a/tests/test_rocket_powered_landing.py +++ /dev/null @@ -1,20 +0,0 @@ -import conftest # Add root path to sys.path -import numpy as np -from numpy.testing import suppress_warnings - -from AerialNavigation.rocket_powered_landing import rocket_powered_landing as m - - -def test1(): - m.show_animation = False - with suppress_warnings() as sup: - sup.filter(UserWarning, - "You are solving a parameterized problem that is not DPP" - ) - sup.filter(UserWarning, - "Solution may be inaccurate") - m.main(rng=np.random.default_rng(1234)) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt.py b/tests/test_rrt.py deleted file mode 100644 index 14a81759315..00000000000 --- a/tests/test_rrt.py +++ /dev/null @@ -1,21 +0,0 @@ -import conftest -import random - -from PathPlanning.RRT import rrt as m -from PathPlanning.RRT import rrt_with_pathsmoothing as m1 - -random.seed(12345) - - -def test1(): - m.show_animation = False - m.main(gx=1.0, gy=1.0) - - -def test2(): - m1.show_animation = False - m1.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt_dubins.py b/tests/test_rrt_dubins.py deleted file mode 100644 index 66130484bc1..00000000000 --- a/tests/test_rrt_dubins.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.RRTDubins import rrt_dubins as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt_star.py b/tests/test_rrt_star.py deleted file mode 100644 index 232995ecb42..00000000000 --- a/tests/test_rrt_star.py +++ /dev/null @@ -1,36 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.RRTStar import rrt_star as m - - -def test1(): - m.show_animation = False - m.main() - - -def test_no_obstacle(): - obstacle_list = [] - - # Set Initial parameters - rrt_star = m.RRTStar(start=[0, 0], - goal=[6, 10], - rand_area=[-2, 15], - obstacle_list=obstacle_list) - path = rrt_star.planning(animation=False) - assert path is not None - - -def test_no_obstacle_and_robot_radius(): - obstacle_list = [] - - # Set Initial parameters - rrt_star = m.RRTStar(start=[0, 0], - goal=[6, 10], - rand_area=[-2, 15], - obstacle_list=obstacle_list, - robot_radius=0.8) - path = rrt_star.planning(animation=False) - assert path is not None - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt_star_dubins.py b/tests/test_rrt_star_dubins.py deleted file mode 100644 index c55ca23e43d..00000000000 --- a/tests/test_rrt_star_dubins.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.RRTStarDubins import rrt_star_dubins as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt_star_reeds_shepp.py b/tests/test_rrt_star_reeds_shepp.py deleted file mode 100644 index 11157aa57ae..00000000000 --- a/tests/test_rrt_star_reeds_shepp.py +++ /dev/null @@ -1,46 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.RRTStarReedsShepp import rrt_star_reeds_shepp as m - - -def test1(): - m.show_animation = False - m.main(max_iter=5) - -obstacleList = [ - (5, 5, 1), - (4, 6, 1), - (4, 8, 1), - (4, 10, 1), - (6, 5, 1), - (7, 5, 1), - (8, 6, 1), - (8, 8, 1), - (8, 10, 1) -] # [x,y,size(radius)] - -start = [0.0, 0.0, m.np.deg2rad(0.0)] -goal = [6.0, 7.0, m.np.deg2rad(90.0)] - -def test2(): - step_size = 0.2 - rrt_star_reeds_shepp = m.RRTStarReedsShepp(start, goal, - obstacleList, [-2.0, 15.0], - max_iter=100, step_size=step_size) - rrt_star_reeds_shepp.set_random_seed(seed=8) - path = rrt_star_reeds_shepp.planning(animation=False) - for i in range(len(path)-1): - # + 0.00000000000001 for acceptable errors arising from the planning process - assert m.math.dist(path[i][0:2], path[i+1][0:2]) < step_size + 0.00000000000001 - -def test_too_big_step_size(): - step_size = 20 - rrt_star_reeds_shepp = m.RRTStarReedsShepp(start, goal, - obstacleList, [-2.0, 15.0], - max_iter=100, step_size=step_size) - rrt_star_reeds_shepp.set_random_seed(seed=8) - path = rrt_star_reeds_shepp.planning(animation=False) - assert path is None - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt_star_seven_joint_arm.py b/tests/test_rrt_star_seven_joint_arm.py deleted file mode 100644 index 2f6622cf6cf..00000000000 --- a/tests/test_rrt_star_seven_joint_arm.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest # Add root path to sys.path -from ArmNavigation.rrt_star_seven_joint_arm_control \ - import rrt_star_seven_joint_arm_control as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_rrt_with_sobol_sampler.py b/tests/test_rrt_with_sobol_sampler.py deleted file mode 100644 index affe2b165a6..00000000000 --- a/tests/test_rrt_with_sobol_sampler.py +++ /dev/null @@ -1,14 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.RRT import rrt_with_sobol_sampler as m -import random - -random.seed(12345) - - -def test1(): - m.show_animation = False - m.main(gx=1.0, gy=1.0) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_safe_interval_path_planner.py b/tests/test_safe_interval_path_planner.py deleted file mode 100644 index f1fbf90d2a8..00000000000 --- a/tests/test_safe_interval_path_planner.py +++ /dev/null @@ -1,33 +0,0 @@ -from PathPlanning.TimeBasedPathPlanning.GridWithDynamicObstacles import ( - Grid, - ObstacleArrangement, - Position, -) -from PathPlanning.TimeBasedPathPlanning import SafeInterval as m -import numpy as np -import conftest - - -def test_1(): - start = Position(1, 11) - goal = Position(19, 19) - grid_side_length = 21 - grid = Grid( - np.array([grid_side_length, grid_side_length]), - obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1, - ) - - m.show_animation = False - planner = m.SafeIntervalPathPlanner(grid, start, goal) - - path = planner.plan(False) - - # path should have 31 entries - assert len(path.path) == 31 - - # path should end at the goal - assert path.path[-1].position == goal - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_space_time_astar.py b/tests/test_space_time_astar.py deleted file mode 100644 index 390c7732dcd..00000000000 --- a/tests/test_space_time_astar.py +++ /dev/null @@ -1,34 +0,0 @@ -from PathPlanning.TimeBasedPathPlanning.GridWithDynamicObstacles import ( - Grid, - ObstacleArrangement, - Position, -) -from PathPlanning.TimeBasedPathPlanning import SpaceTimeAStar as m -import numpy as np -import conftest - - -def test_1(): - start = Position(1, 11) - goal = Position(19, 19) - grid_side_length = 21 - grid = Grid( - np.array([grid_side_length, grid_side_length]), - obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1, - ) - - m.show_animation = False - planner = m.SpaceTimeAStar(grid, start, goal) - - path = planner.plan(False) - - # path should have 28 entries - assert len(path.path) == 31 - - # path should end at the goal - assert path.path[-1].position == goal - - assert planner.expanded_node_count < 1000 - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_spiral_spanning_tree_coverage_path_planner.py b/tests/test_spiral_spanning_tree_coverage_path_planner.py deleted file mode 100644 index 44170fa4cc3..00000000000 --- a/tests/test_spiral_spanning_tree_coverage_path_planner.py +++ /dev/null @@ -1,58 +0,0 @@ -import conftest # Add root path to sys.path -import os -import matplotlib.pyplot as plt -from PathPlanning.SpiralSpanningTreeCPP \ - import spiral_spanning_tree_coverage_path_planner - -spiral_spanning_tree_coverage_path_planner.do_animation = True - - -def spiral_stc_cpp(img, start): - num_free = 0 - for i in range(img.shape[0]): - for j in range(img.shape[1]): - num_free += img[i][j] - - STC_planner = spiral_spanning_tree_coverage_path_planner.\ - SpiralSpanningTreeCoveragePlanner(img) - - edge, route, path = STC_planner.plan(start) - - covered_nodes = set() - for p, q in edge: - covered_nodes.add(p) - covered_nodes.add(q) - - # assert complete coverage - assert len(covered_nodes) == num_free / 4 - - -def test_spiral_stc_cpp_1(): - img_dir = os.path.dirname( - os.path.abspath(__file__)) + \ - "/../PathPlanning/SpiralSpanningTreeCPP" - img = plt.imread(os.path.join(img_dir, 'map', 'test.png')) - start = (0, 0) - spiral_stc_cpp(img, start) - - -def test_spiral_stc_cpp_2(): - img_dir = os.path.dirname( - os.path.abspath(__file__)) + \ - "/../PathPlanning/SpiralSpanningTreeCPP" - img = plt.imread(os.path.join(img_dir, 'map', 'test_2.png')) - start = (10, 0) - spiral_stc_cpp(img, start) - - -def test_spiral_stc_cpp_3(): - img_dir = os.path.dirname( - os.path.abspath(__file__)) + \ - "/../PathPlanning/SpiralSpanningTreeCPP" - img = plt.imread(os.path.join(img_dir, 'map', 'test_3.png')) - start = (0, 0) - spiral_stc_cpp(img, start) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_stanley_controller.py b/tests/test_stanley_controller.py deleted file mode 100644 index a1d8073764e..00000000000 --- a/tests/test_stanley_controller.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathTracking.stanley_controller import stanley_controller as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_state_lattice_planner.py b/tests/test_state_lattice_planner.py deleted file mode 100644 index 0c14222e815..00000000000 --- a/tests/test_state_lattice_planner.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.StateLatticePlanner import state_lattice_planner as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_state_machine.py b/tests/test_state_machine.py deleted file mode 100644 index e36a8120fd5..00000000000 --- a/tests/test_state_machine.py +++ /dev/null @@ -1,51 +0,0 @@ -import conftest - -from MissionPlanning.StateMachine.state_machine import StateMachine - - -def test_transition(): - sm = StateMachine("state_machine") - sm.add_transition(src_state="idle", event="start", dst_state="running") - sm.set_current_state("idle") - sm.process("start") - assert sm.get_current_state().name == "running" - - -def test_guard(): - class Model: - def can_start(self): - return False - - sm = StateMachine("state_machine", Model()) - sm.add_transition( - src_state="idle", event="start", dst_state="running", guard="can_start" - ) - sm.set_current_state("idle") - sm.process("start") - assert sm.get_current_state().name == "idle" - - -def test_action(): - class Model: - def on_start(self): - self.start_called = True - - model = Model() - sm = StateMachine("state_machine", model) - sm.add_transition( - src_state="idle", event="start", dst_state="running", action="on_start" - ) - sm.set_current_state("idle") - sm.process("start") - assert model.start_called - - -def test_plantuml(): - sm = StateMachine("state_machine") - sm.add_transition(src_state="idle", event="start", dst_state="running") - sm.set_current_state("idle") - assert sm.generate_plantuml() - - -if __name__ == "__main__": - conftest.run_this_test(__file__) diff --git a/tests/test_two_joint_arm_to_point_control.py b/tests/test_two_joint_arm_to_point_control.py deleted file mode 100644 index 1de4fcd8057..00000000000 --- a/tests/test_two_joint_arm_to_point_control.py +++ /dev/null @@ -1,12 +0,0 @@ -import conftest # Add root path to sys.path -from ArmNavigation.two_joint_arm_to_point_control \ - import two_joint_arm_to_point_control as m - - -def test1(): - m.show_animation = False - m.animation() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_unscented_kalman_filter.py b/tests/test_unscented_kalman_filter.py deleted file mode 100644 index b7dda6e2761..00000000000 --- a/tests/test_unscented_kalman_filter.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from Localization.unscented_kalman_filter import unscented_kalman_filter as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index 36861c52b45..00000000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,27 +0,0 @@ -import conftest # Add root path to sys.path -from utils import angle -from numpy.testing import assert_allclose -import numpy as np - - -def test_rot_mat_2d(): - assert_allclose(angle.rot_mat_2d(0.0), - np.array([[1., 0.], - [0., 1.]])) - - -def test_angle_mod(): - assert_allclose(angle.angle_mod(-4.0), 2.28318531) - assert(isinstance(angle.angle_mod(-4.0), float)) - assert_allclose(angle.angle_mod([-4.0]), [2.28318531]) - assert(isinstance(angle.angle_mod([-4.0]), np.ndarray)) - - assert_allclose(angle.angle_mod([-150.0, 190.0, 350], degree=True), - [-150., -170., -10.]) - - assert_allclose(angle.angle_mod(-60.0, zero_2_2pi=True, degree=True), - [300.]) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_visibility_road_map_planner.py b/tests/test_visibility_road_map_planner.py deleted file mode 100644 index 5a663d289d2..00000000000 --- a/tests/test_visibility_road_map_planner.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.VoronoiRoadMap import voronoi_road_map as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_voronoi_road_map_planner.py b/tests/test_voronoi_road_map_planner.py deleted file mode 100644 index b0b7550fb2f..00000000000 --- a/tests/test_voronoi_road_map_planner.py +++ /dev/null @@ -1,11 +0,0 @@ -import conftest # Add root path to sys.path -from PathPlanning.VisibilityRoadMap import visibility_road_map as m - - -def test1(): - m.show_animation = False - m.main() - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/tests/test_wavefront_coverage_path_planner.py b/tests/test_wavefront_coverage_path_planner.py deleted file mode 100644 index 28bb5987e7f..00000000000 --- a/tests/test_wavefront_coverage_path_planner.py +++ /dev/null @@ -1,63 +0,0 @@ -import conftest # Add root path to sys.path -import os -import matplotlib.pyplot as plt -from PathPlanning.WavefrontCPP import wavefront_coverage_path_planner - -wavefront_coverage_path_planner.do_animation = False - - -def wavefront_cpp(img, start, goal): - num_free = 0 - for i in range(img.shape[0]): - for j in range(img.shape[1]): - num_free += 1 - img[i][j] - - DT = wavefront_coverage_path_planner.transform( - img, goal, transform_type='distance') - DT_path = wavefront_coverage_path_planner.wavefront(DT, start, goal) - assert len(DT_path) == num_free # assert complete coverage - - PT = wavefront_coverage_path_planner.transform( - img, goal, transform_type='path', alpha=0.01) - PT_path = wavefront_coverage_path_planner.wavefront(PT, start, goal) - assert len(PT_path) == num_free # assert complete coverage - - -def test_wavefront_CPP_1(): - img_dir = os.path.dirname( - os.path.abspath(__file__)) + "/../PathPlanning/WavefrontCPP" - img = plt.imread(os.path.join(img_dir, 'map', 'test.png')) - img = 1 - img - - start = (43, 0) - goal = (0, 0) - - wavefront_cpp(img, start, goal) - - -def test_wavefront_CPP_2(): - img_dir = os.path.dirname( - os.path.abspath(__file__)) + "/../PathPlanning/WavefrontCPP" - img = plt.imread(os.path.join(img_dir, 'map', 'test_2.png')) - img = 1 - img - - start = (10, 0) - goal = (10, 40) - - wavefront_cpp(img, start, goal) - - -def test_wavefront_CPP_3(): - img_dir = os.path.dirname( - os.path.abspath(__file__)) + "/../PathPlanning/WavefrontCPP" - img = plt.imread(os.path.join(img_dir, 'map', 'test_3.png')) - img = 1 - img - - start = (0, 0) - goal = (30, 30) - - wavefront_cpp(img, start, goal) - - -if __name__ == '__main__': - conftest.run_this_test(__file__) diff --git a/users_comments.md b/users_comments.md deleted file mode 100644 index a2f798eac46..00000000000 --- a/users_comments.md +++ /dev/null @@ -1,415 +0,0 @@ -# User's demos - -## WHILL MODEL CR with move to a pose control - -This is an electric wheelchair control demo by [Katsushun89](https://github.com/Katsushun89). - -[WHILL Model CR](https://whill.jp/model-cr) is the control target, [M5Stack](https://m5stack.com/) is used for the controller, and [toio](https://toio.io/) is used for the control input device. - -[Move to a Pose Control — PythonRobotics documentation](https://atsushisakai.github.io/PythonRobotics/modules/control/move_to_a_pose_control/move_to_a_pose_control.html) is used for its control algorithm ([code link](https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathTracking/move_to_pose/move_to_pose.py)). - - - -Ref: - -- [toioと同じように動くWHILL Model CR (in Japanese)](https://qiita.com/KatsuShun89/items/68fde7544ecfe36096d2) - - -# Educational users - -If you found users who are using PythonRobotics for education, please make an issue to let me know. - -# Stargazers location map - -You can check stargazer's locations of this project from: - -- [Stargazers location map](https://drive.google.com/open?id=1bBXS9IQmZ3Tfe1wNGvJbObRt9Htt4PGC&usp=sharing) - - -# Related projects - -This is a list of related projects. - -- [onlytailei/CppRobotics: cpp implementation of robotics algorithms including localization, mapping, SLAM, path planning and control](https://github.com/onlytailei/CppRobotics) - -# Individual users comments - ---- - -Dear AtsushiSakai, <br>thank you for building this cool repo for robotics. <br>I am still learning robotics and this will give me a good starting point. <br>I hope this note gets to you. <br> <br> - ---David Senicic - ---- - -Dear AtsushiSakai, <br>WE found your project from google when first searching for a rosbag to csv converter. We are a small team in MCity working on Connected (and Automated) vehicles. We are working with an opensource platform that serve as the AI to control the vehicle. Your code and documentation helped us a lot! <br> <br>Thank you! Have a nice day! - ---Hanlin(Julia) Chen, MCity Apollo team - ---- - -Dear Atsushi Sakai, <br> <br>With your simplistic descriptions in text and as gifs, i was able to help my students understand easily and effectively, I would be honored to help, in anyway towards this, As a hobbyist have been developing lidar based slam navigation systems from 2011 and its only right to acknowledge and thank you for your contributions. - ---Shiva - ---- - -Dear Atsushi Sakai <br>I first came across your Matlab repository on ICP and SLAM. The repository for both python and Matlab helped me in understanding the essential concepts of robotics.I am really grateful to you for helping me develop my understanding of the concepts of robotics. - ---Sparsh Garg - ---- - -Dear AtsushiSakai, <br>Thank you very much for all the example programs related to Robotics - ---Kalyan - ---- -Dear AtsushiSakai, <br> <br>Thanks for Python Robotics - ---Rebecca Li - ---- - -Thanks alot. - ---Zain - ---- - -Dear AtsushiSakai,<br> <br>thank you for you code! - -—- Anonymous - ---- - -Thanks! - ---a friend - ---- - -Thanks for the awesome collection of codes! - ---Qi - ---- - -Thank you! - ---huang pingzhong - ---- - -Dear AtsushiSakai, <br>Thanks a lot for the wonderful collection of projects.It was really useful. I really appreciate your time in maintaing and building this repository.It will be really great if I get a chance to meet you in person sometime.I got really inspired looking at your work. <br>All the very best for all your future endeavors! <br> Thanks once again, <br> - ----Ezhil Bharathi - ---- - -Dear Atsushi Sakai, <br>Thank you so much for gathering all the useful stuff and good examples of robotics things ! :) <br>I am very new in this area and want to know more about robotics and SLAM things. <br>and again, thank you so much :) <br> - ---Tutorgaming - ---- - -Dear AtsushiSakai, <br>Very excellent work. Thank you for your share. - ---Thomas Yang - ---- - -Dear Atsushi Saka Arigato 🤗🤗 - ---Badal Kumar - ---- - -Dear AtsushiSakai, <br>Thanks for teaching how to implement path planning algorithms in robotics. <br> - ---- - -Your Github page is very useful. I will apply it with cooperative robot. - ---Soloist - ---- - -help me very much thankyou - ---sanchuan - ---- - -Dear AtsushiSakai, <br>U R so niubility! - ---FangKD - ---- - -thankyou AtsushiSakai! - ---ou minghua - ---- - -Dear AtsushiSakai <br>Thank You - ---Dogukan Altay - ---- - -so kind of you can you make videos of it. - ---- - -Dear AtshshiSakai, <br>You are very wise and smart that you created this library for students wanting to learn Probabilistic Robotics and actually perform robot control. <br>Hats off to you and your work. <br>I am also reading your book titled : Python Robotics - ---Himanshu - ---- - -Dear AtsushiSakai, <br>Hello! YOUR CODE IS SUPER SUPER HELPFUL AND GIVES ME CLEAR INSTRUCTIONs as well as STRONG SUPPORT!! <br>Thank you so much ! - ---Lee - ---- - -Hi AtsushiSakai, <br> <br>Thanks for creating the pythonrobotics repo! It's an awesome repo that has been of great help to me. I've referenced your extended kalman filter algorithm while creating my own for localization using a 2D lidar, camera, and IMU. Our robot is destined to compete soon, so fingers crossed that all works out! Thanks again. - ---- - -You rock! - ---Matt - ---- - -Dear AtsushiSakai, <br>You are the best. This is by far the best tutorial for learning and implementing robotics. <br>Thanks a lot for your time and efforts to do this! - ---Adi B - ---- - -Dear Atushi, thank you for this amazing repository. It is a pleasure to have access to python algorithms without the burden of ROS. While I'm no longer working on such robotics projects, it's wonderful to know its available when I need it and it was amazing to see all the beautiful animations for each algorithm. - ---Shreeyak Sajjan - ---- - -Dear AtsushiSakai <br>Thank you for your contributions! - ---Luo - ---- - -Dear AtsushiSakai, Your visualizations are awesome, and I am going to have this link bookmarked for future references. Thank you! - ---Srinivasa Varadhan Agaram Chakravarthy - ---- - -Dear AtsushiSakai, <br>Thank you for this great resource! I very much appreciate all your hard work and effort. - ---Mridul Aanjaneya - ---- - -Thank you for the python robotics sample code and visualizations!! This is my new favorite thing on the internet. - ---selamg@mit.edu - ---- - -Mr AtsushiSakai .. <br>Your work and teaching is light for me <br>thank you very much for giving time and effort to make it public for us - ---Karim Anass - ---- - -Thank You - ---Anonymous - ---- - -I've learned the robotics from the traditional way of solving problem through finding packages and reading papers. This amazing project is unbelievably helpful for new-comers to learn and get familiar with the algorithms. Gods know how many hours you've taken to sort all the materials and written everything into one single coherent project. I'm truly amazed and deepest appreciation. - ---Ewing Kang - ---- - -Hey, I'm a student and I just recently got into robotics, and visited your repository multiple times. Today I was super happy to find the link to Patreon! I am impressed by didactic quality of the repo, keep up the good work! - ---Carolina Bianchi - ---- - -Dear AtsushiSakai, thanks a lot for the PythonRobotics git repository. I'm a college student who is trying to make a mini autonomous robot for my final project submission, I still haven't started using your code but by the look of it I'm sure it will be of greater use. Will let you know how my project is coming up. - ---Pragdheesh - ---- - -Hello AtsushiSakai, <br> <br>Thank you very much for sharing your work! - ---Uma K - ---- - -Hey Atsushi <br>We are working on a multiagent simulation game and this project gave us really good insights. <br>In future, I would like to contribute to this project with our multiagent task allocation among robots and multi robot map merging( Which is a big hurdle as we found). <br>Thanks for what you are doing for open source. <br> - ---Mayank - ---- - -Thanks a lot for this amazing set of very useful librarires! - ---Razvan Viorel Mihai - ---- - -Dear Atsushi Sakai, <br> <br>This is probably one of the best open-source robotics based Algorithms I have seen so far. Thank you for posting this knowledge with other engineers. It will definitely help soon to become engineers like myself. - ---Don - ---- - -hanks frnd, for ur contibusion - -—-- - -Thank you for python robotics!! - ---Manuel Miguez - ---- - -Great job - ---Anonymous - ---- - -Dear Atsushi Sakai <br>Thank you for the Python Robotics - ---Alex Liberzon - ---- - -Thanks for your robotics repo! - ---Mithi - ---- - -You made such a nice work. Congratulations :) - ---ATroya - ---- - -thank you for python path finding repo - ---fengzongbao - ---- - -Dear AtsushiSakai, <br> <br>Thank you so much for making the concept of robotics approachable for the general mass. Keep up the good work :) - ---Harsh Munshi - ---- - -Benefit a lot for your GitHub repository of PythonRobotics. Thanks so much. - ---Haoran - ---- - -Thanks! - ---Reinzor - ---- - -Thanks for writing these algorithms. They are very helpful for learning robotics. - ---Arihant Lunawat - ---- - -Dear AtsushiSakai, <br>Thank you for providing us this great repository for playing and look around:)! - ---Hsin-Wen - ---- - -Thanks for PythonRobotics! - ---Nick V - ---- - -Dear AtsushiSakai, thank you so much for this material, it's so useful to me, i'm really glad with it =D - ---Juanda - ---- - -Dear Atsushi Thanks for compiling such a vast resource for robotics motion planning. - ---Kartik Prakash - ---- - -Thanks for your job! <br>I have learned a lot from it! - ---ZhongyiShen - ---- - -Dear Atsushi Sakai, <br>Thank you so much for creating PythonRobotics and documenting it so well. I am a senior in high school trying to learn and better myself in these concepts. - ---Rohan Mathur - - - -# Citations - -1. B. Blaga, M. Deac, R. W. Y. Al-doori, M. Negru and R. Dǎnescu, "Miniature Autonomous Vehicle Development on Raspberry Pi," 2018 IEEE 14th International Conference on Intelligent Computer Communication and Processing (ICCP), Cluj-Napoca, Romania, 2018, pp. 229-236. -doi: 10.1109/ICCP.2018.8516589 -keywords: {Automobiles;Task analysis;Autonomous vehicles;Path planning;Global Positioning System;Cameras;miniature autonomous vehicle;path planning;navigation;parking assist;lane detection and tracking;traffic sign recognition}, -URL: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8516589&isnumber=8516425 - -2. Peggy (Yuchun) Wang and Caitlin Hogan, "Path Planning with Dynamic Obstacle Avoidance for a Jumping-Enabled Robot", AA228/CS238 class report, Department of Computer Science, Stanford University, URL: https://web.stanford.edu/class/aa228/reports/2018/final113.pdf - -3. Welburn, E, Hakim Khalili, H, Gupta, A, Watson, S & Carrasco, J 2019, A Navigational System for Quadcopter Remote Inspection of Offshore Substations. in The Fifteenth International Conference on Autonomic and Autonomous Systems 2019. URL:https://research.manchester.ac.uk/portal/files/107169964/ICAS19_A_Navigational_System_for_Quadcopter_Remote_Inspection_of_Offshore_Substations.pdf - -4. E. Horváth, C. Hajdu, C. Radu and Á. Ballagi, "Range Sensor-based Occupancy Grid Mapping with Signatures," 2019 20th International Carpathian Control Conference (ICCC), Krakow-Wieliczka, Poland, 2019, pp. 1-5. -URL: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8765684&isnumber=8765679 - -5. Josie Hughes, Masaru Shimizu, and Arnoud Visser, "A Review of Robot Rescue Simulation Platforms for Robotics Education" -URL: https://2019.robocup.org/downloads/program/HughesEtAl2019.pdf - -6. Hughes, Josie, Masaru Shimizu, and Arnoud Visser. "A review of robot rescue simulation platforms for robotics education." (2019). -URL: https://www.semanticscholar.org/paper/A-Review-of-Robot-Rescue-Simulation-Platforms-for-Hughes-Shimizu/318a4bcb97a44661422ae1430d950efc408097da - -7. Ghosh, Ritwika, et al. "CyPhyHouse: A Programming, Simulation, and Deployment Toolchain for Heterogeneous Distributed Coordination." arXiv preprint arXiv:1910.01557 (2019). -URL: https://arxiv.org/abs/1910.01557 - -8. Hahn, Carsten, et al. "Dynamic Path Planning with Stable Growing Neural Gas." (2019). -URL: https://pdfs.semanticscholar.org/5c06/f3cb9542a51e1bf1a32523c1bc7fea6cecc5.pdf - -9. Brijen Thananjeyan, et al. "ABC-LMPC: Safe Sample-Based Learning MPC for Stochastic Nonlinear Dynamical Systems with Adjustable Boundary Conditions" -URL: https://arxiv.org/pdf/2003.01410 - -# Others - -- Autonomous Vehicle Readings https://richardkelley.io/readings - -- 36 Amazing Python Open Source Projects (v.2019) – Mybridge for Professionals https://medium.mybridge.co/36-amazing-python-open-source-projects-v-2019-2fe058d79450 - -- Real-time Model Predictive Control (MPC), ACADO, Python | Work-is-Playing http://grauonline.de/wordpress/?page_id=3244 - -- 💡 Greatest of GitHub - Python Robotics (Amazing!) - YouTube https://www.youtube.com/watch?v=f_pPaYx6Gu0&feature=emb_logo diff --git a/utils/__init__.py b/utils/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/utils/angle.py b/utils/angle.py deleted file mode 100644 index c9e02c5f2e7..00000000000 --- a/utils/angle.py +++ /dev/null @@ -1,83 +0,0 @@ -import numpy as np -from scipy.spatial.transform import Rotation as Rot - - -def rot_mat_2d(angle): - """ - Create 2D rotation matrix from an angle - - Parameters - ---------- - angle : - - Returns - ------- - A 2D rotation matrix - - Examples - -------- - >>> angle_mod(-4.0) - - - """ - return Rot.from_euler('z', angle).as_matrix()[0:2, 0:2] - - -def angle_mod(x, zero_2_2pi=False, degree=False): - """ - Angle modulo operation - Default angle modulo range is [-pi, pi) - - Parameters - ---------- - x : float or array_like - A angle or an array of angles. This array is flattened for - the calculation. When an angle is provided, a float angle is returned. - zero_2_2pi : bool, optional - Change angle modulo range to [0, 2pi) - Default is False. - degree : bool, optional - If True, then the given angles are assumed to be in degrees. - Default is False. - - Returns - ------- - ret : float or ndarray - an angle or an array of modulated angle. - - Examples - -------- - >>> angle_mod(-4.0) - 2.28318531 - - >>> angle_mod([-4.0]) - np.array(2.28318531) - - >>> angle_mod([-150.0, 190.0, 350], degree=True) - array([-150., -170., -10.]) - - >>> angle_mod(-60.0, zero_2_2pi=True, degree=True) - array([300.]) - - """ - if isinstance(x, float): - is_float = True - else: - is_float = False - - x = np.asarray(x).flatten() - if degree: - x = np.deg2rad(x) - - if zero_2_2pi: - mod_angle = x % (2 * np.pi) - else: - mod_angle = (x + np.pi) % (2 * np.pi) - np.pi - - if degree: - mod_angle = np.rad2deg(mod_angle) - - if is_float: - return mod_angle.item() - else: - return mod_angle diff --git a/utils/plot.py b/utils/plot.py deleted file mode 100644 index eb5aa7ad048..00000000000 --- a/utils/plot.py +++ /dev/null @@ -1,234 +0,0 @@ -""" -Matplotlib based plotting utilities -""" -import math -import matplotlib.pyplot as plt -import numpy as np -from mpl_toolkits.mplot3d import art3d -from matplotlib.patches import FancyArrowPatch -from mpl_toolkits.mplot3d.proj3d import proj_transform -from mpl_toolkits.mplot3d import Axes3D - -from utils.angle import rot_mat_2d - - -def plot_covariance_ellipse(x, y, cov, chi2=3.0, color="-r", ax=None): - """ - This function plots an ellipse that represents a covariance matrix. The ellipse is centered at (x, y) and its shape, size and rotation are determined by the covariance matrix. - - Parameters: - x : (float) The x-coordinate of the center of the ellipse. - y : (float) The y-coordinate of the center of the ellipse. - cov : (numpy.ndarray) A 2x2 covariance matrix that determines the shape, size, and rotation of the ellipse. - chi2 : (float, optional) A scalar value that scales the ellipse size. This value is typically set based on chi-squared distribution quantiles to achieve certain confidence levels (e.g., 3.0 corresponds to ~95% confidence for a 2D Gaussian). Defaults to 3.0. - color : (str, optional) The color and line style of the ellipse plot, following matplotlib conventions. Defaults to "-r" (a red solid line). - ax : (matplotlib.axes.Axes, optional) The Axes object to draw the ellipse on. If None (default), a new figure and axes are created. - - Returns: - None. This function plots the covariance ellipse on the specified axes. - """ - eig_val, eig_vec = np.linalg.eig(cov) - - if eig_val[0] >= eig_val[1]: - big_ind = 0 - small_ind = 1 - else: - big_ind = 1 - small_ind = 0 - a = math.sqrt(chi2 * eig_val[big_ind]) - b = math.sqrt(chi2 * eig_val[small_ind]) - angle = math.atan2(eig_vec[1, big_ind], eig_vec[0, big_ind]) - plot_ellipse(x, y, a, b, angle, color=color, ax=ax) - - -def plot_ellipse(x, y, a, b, angle, color="-r", ax=None, **kwargs): - """ - This function plots an ellipse based on the given parameters. - - Parameters - ---------- - x : (float) The x-coordinate of the center of the ellipse. - y : (float) The y-coordinate of the center of the ellipse. - a : (float) The length of the semi-major axis of the ellipse. - b : (float) The length of the semi-minor axis of the ellipse. - angle : (float) The rotation angle of the ellipse, in radians. - color : (str, optional) The color and line style of the ellipse plot, following matplotlib conventions. Defaults to "-r" (a red solid line). - ax : (matplotlib.axes.Axes, optional) The Axes object to draw the ellipse on. If None (default), a new figure and axes are created. - **kwargs: Additional keyword arguments to pass to plt.plot or ax.plot. - - Returns - --------- - None. This function plots the ellipse based on the specified parameters. - """ - - t = np.arange(0, 2 * math.pi + 0.1, 0.1) - px = [a * math.cos(it) for it in t] - py = [b * math.sin(it) for it in t] - fx = rot_mat_2d(angle) @ (np.array([px, py])) - px = np.array(fx[0, :] + x).flatten() - py = np.array(fx[1, :] + y).flatten() - if ax is None: - plt.plot(px, py, color, **kwargs) - else: - ax.plot(px, py, color, **kwargs) - - -def plot_arrow(x, y, yaw, arrow_length=1.0, - origin_point_plot_style="xr", - head_width=0.1, fc="r", ec="k", **kwargs): - """ - Plot an arrow or arrows based on 2D state (x, y, yaw) - - All optional settings of matplotlib.pyplot.arrow can be used. - - matplotlib.pyplot.arrow: - https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.arrow.html - - Parameters - ---------- - x : a float or array_like - a value or a list of arrow origin x position. - y : a float or array_like - a value or a list of arrow origin y position. - yaw : a float or array_like - a value or a list of arrow yaw angle (orientation). - arrow_length : a float (optional) - arrow length. default is 1.0 - origin_point_plot_style : str (optional) - origin point plot style. If None, not plotting. - head_width : a float (optional) - arrow head width. default is 0.1 - fc : string (optional) - face color - ec : string (optional) - edge color - """ - if not isinstance(x, float): - for (i_x, i_y, i_yaw) in zip(x, y, yaw): - plot_arrow(i_x, i_y, i_yaw, head_width=head_width, - fc=fc, ec=ec, **kwargs) - else: - plt.arrow(x, y, - arrow_length * math.cos(yaw), - arrow_length * math.sin(yaw), - head_width=head_width, - fc=fc, ec=ec, - **kwargs) - if origin_point_plot_style is not None: - plt.plot(x, y, origin_point_plot_style) - - -def plot_curvature(x_list, y_list, heading_list, curvature, - k=0.01, c="-c", label="Curvature"): - """ - Plot curvature on 2D path. This plot is a line from the original path, - the lateral distance from the original path shows curvature magnitude. - Left turning shows right side plot, right turning shows left side plot. - For straight path, the curvature plot will be on the path, because - curvature is 0 on the straight path. - - Parameters - ---------- - x_list : array_like - x position list of the path - y_list : array_like - y position list of the path - heading_list : array_like - heading list of the path - curvature : array_like - curvature list of the path - k : float - curvature scale factor to calculate distance from the original path - c : string - color of the plot - label : string - label of the plot - """ - cx = [x + d * k * np.cos(yaw - np.pi / 2.0) for x, y, yaw, d in - zip(x_list, y_list, heading_list, curvature)] - cy = [y + d * k * np.sin(yaw - np.pi / 2.0) for x, y, yaw, d in - zip(x_list, y_list, heading_list, curvature)] - - plt.plot(cx, cy, c, label=label) - for ix, iy, icx, icy in zip(x_list, y_list, cx, cy): - plt.plot([ix, icx], [iy, icy], c) - - -class Arrow3D(FancyArrowPatch): - - def __init__(self, x, y, z, dx, dy, dz, *args, **kwargs): - super().__init__((0, 0), (0, 0), *args, **kwargs) - self._xyz = (x, y, z) - self._dxdydz = (dx, dy, dz) - - def draw(self, renderer): - x1, y1, z1 = self._xyz - dx, dy, dz = self._dxdydz - x2, y2, z2 = (x1 + dx, y1 + dy, z1 + dz) - - xs, ys, zs = proj_transform((x1, x2), (y1, y2), (z1, z2), self.axes.M) - self.set_positions((xs[0], ys[0]), (xs[1], ys[1])) - super().draw(renderer) - - def do_3d_projection(self, renderer=None): - x1, y1, z1 = self._xyz - dx, dy, dz = self._dxdydz - x2, y2, z2 = (x1 + dx, y1 + dy, z1 + dz) - - xs, ys, zs = proj_transform((x1, x2), (y1, y2), (z1, z2), self.axes.M) - self.set_positions((xs[0], ys[0]), (xs[1], ys[1])) - - return np.min(zs) - - -def _arrow3D(ax, x, y, z, dx, dy, dz, *args, **kwargs): - '''Add an 3d arrow to an `Axes3D` instance.''' - arrow = Arrow3D(x, y, z, dx, dy, dz, *args, **kwargs) - ax.add_artist(arrow) - - -def plot_3d_vector_arrow(ax, p1, p2): - setattr(Axes3D, 'arrow3D', _arrow3D) - ax.arrow3D(p1[0], p1[1], p1[2], - p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2], - mutation_scale=20, - arrowstyle="-|>", - ) - - -def plot_triangle(p1, p2, p3, ax): - ax.add_collection3d(art3d.Poly3DCollection([[p1, p2, p3]], color='b')) - - -def set_equal_3d_axis(ax, x_lims, y_lims, z_lims): - """Helper function to set equal axis - - Args: - ax (Axes3DSubplot): matplotlib 3D axis, created by - `ax = fig.add_subplot(projection='3d')` - x_lims (np.array): array containing min and max value of x - y_lims (np.array): array containing min and max value of y - z_lims (np.array): array containing min and max value of z - """ - x_lims = np.asarray(x_lims) - y_lims = np.asarray(y_lims) - z_lims = np.asarray(z_lims) - # compute max required range - max_range = np.array([x_lims.max() - x_lims.min(), - y_lims.max() - y_lims.min(), - z_lims.max() - z_lims.min()]).max() / 2.0 - # compute mid-point along each axis - mid_x = (x_lims.max() + x_lims.min()) * 0.5 - mid_y = (y_lims.max() + y_lims.min()) * 0.5 - mid_z = (z_lims.max() + z_lims.min()) * 0.5 - - # set limits to axis - ax.set_xlim(mid_x - max_range, mid_x + max_range) - ax.set_ylim(mid_y - max_range, mid_y + max_range) - ax.set_zlim(mid_z - max_range, mid_z + max_range) - - -if __name__ == '__main__': - plot_ellipse(0, 0, 1, 2, np.deg2rad(15)) - plt.axis('equal') - plt.show() -