python-motion-planning 2.0__tar.gz → 2.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/PKG-INFO +15 -15
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/README.md +14 -14
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/pyproject.toml +1 -1
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/__init__.py +1 -1
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/utils/geometry.py +29 -18
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/__init__.py +9 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/bezier_curve.py +131 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/bspline_curve.py +271 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/cubic_spline.py +128 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/curve.py +64 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/dubins_curve.py +348 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/fem_pos_smooth.py +114 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/polynomial_curve.py +226 -0
- python_motion_planning-2.0.dev2/src/python_motion_planning/curve_generator/reeds_shepp.py +736 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/sample_search/rrt.py +5 -5
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/sample_search/rrt_connect.py +2 -2
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/sample_search/rrt_star.py +11 -31
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning.egg-info/PKG-INFO +15 -15
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning.egg-info/SOURCES.txt +10 -12
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/__init__.py +0 -2
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/base_curve_generator.py +0 -53
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/__init__.py +0 -2
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/point_based/__init__.py +0 -2
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/point_based/bspline.py +0 -256
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/point_based/cubic_spline.py +0 -115
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/pose_based/__init__.py +0 -4
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/pose_based/bezier.py +0 -121
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/pose_based/dubins.py +0 -355
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/pose_based/polynomial.py +0 -197
- python_motion_planning-2.0/src/python_motion_planning/traj_optimizer/curve_generator/pose_based/reeds_shepp.py +0 -606
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/LICENSE +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/setup.cfg +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/map/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/map/base_map.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/map/grid.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/node.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/robot/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/robot/base_robot.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/robot/circular_robot.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/robot/diff_drive_robot.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/types.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/world/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/world/base_world.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/env/world/toy_simulator.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/utils/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/utils/child_tree.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/utils/frame_transformer.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/visualizer/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/visualizer/base_visualizer.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/visualizer/visualizer_2d.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/common/visualizer/visualizer_3d.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/base_controller.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/apf.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/dwa.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/path_tracker.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/pid.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/pure_pursuit.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/path_tracker/rpp.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/controller/random_controller.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/base_path_planner.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/a_star.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/dijkstra.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/gbfs.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/jps.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/lazy_theta_star.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/graph_search/theta_star.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/hybrid_search/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/hybrid_search/voronoi_planner.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning/path_planner/sample_search/__init__.py +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning.egg-info/dependency_links.txt +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning.egg-info/requires.txt +0 -0
- {python_motion_planning-2.0 → python_motion_planning-2.0.dev2}/src/python_motion_planning.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-motion-planning
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.0.dev2
|
|
4
4
|
Summary: Motion planning algorithms for Python
|
|
5
5
|
Maintainer-email: Wu Maojia <omige@mail.nwpu.edu.cn>, Yang Haodong <913982779@qq.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -697,8 +697,6 @@ Dynamic: license-file
|
|
|
697
697
|
|
|
698
698
|
# Introduction
|
|
699
699
|
|
|
700
|
-
`Python Motion Planning` repository provides the implementations of common `Motion planning` algorithms, including path planners on N-D grid, controllers for path-tracking, curve generators, a visualizer based on matplotlib and a toy physical simulator to test controllers.
|
|
701
|
-
|
|
702
700
|
`Motion planning` plans the state sequence of the robot without conflict between the start and goal.
|
|
703
701
|
|
|
704
702
|
`Motion planning` mainly includes `Path planning` and `Trajectory planning`.
|
|
@@ -706,6 +704,8 @@ Dynamic: license-file
|
|
|
706
704
|
* `Path Planning`: It's based on path constraints (such as obstacles), planning the optimal path sequence for the robot to travel without conflict between the start and goal.
|
|
707
705
|
* `Trajectory planning`: It plans the motion state to approach the global path based on kinematics, dynamics constraints and path sequence.
|
|
708
706
|
|
|
707
|
+
This repository provides the implementations of common `Motion planning` algorithms, including path planners on N-D grid and controllers for path-tracking, a visualizer based on matplotlib and a toy physical simulator to test controllers.
|
|
708
|
+
|
|
709
709
|
The theory analysis can be found at [motion-planning](https://blog.csdn.net/frigidwinter/category_11410243.html).
|
|
710
710
|
|
|
711
711
|
We also provide [ROS C++](https://github.com/ai-winter/ros_motion_planning) version and [Matlab](https://github.com/ai-winter/matlab_motion_planning) version.
|
|
@@ -732,8 +732,7 @@ python_motion_planning
|
|
|
732
732
|
| ├─graph_search
|
|
733
733
|
| ├─sample_search
|
|
734
734
|
| └─hybrid_search
|
|
735
|
-
└─
|
|
736
|
-
| └─curve_generator
|
|
735
|
+
└─curve_generator
|
|
737
736
|
```
|
|
738
737
|
|
|
739
738
|
## Install
|
|
@@ -747,7 +746,7 @@ conda activate pmp
|
|
|
747
746
|
To install the repository, please run the following command in shell.
|
|
748
747
|
|
|
749
748
|
```shell
|
|
750
|
-
pip install python-motion-planning
|
|
749
|
+
pip install python-motion-planning==2.0.dev2
|
|
751
750
|
```
|
|
752
751
|
|
|
753
752
|
## Run
|
|
@@ -804,7 +803,7 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
804
803
|
| **PID** ||Not implemented
|
|
805
804
|
| **APF** ||Not implemented
|
|
806
805
|
| **DWA** ||Not implemented
|
|
807
|
-
| **RPP**
|
|
806
|
+
| **RPP** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
808
807
|
| **LQR** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
809
808
|
| **MPC** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
810
809
|
| **MPPI** |Not implemented|Not implemented
|
|
@@ -815,14 +814,17 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
815
814
|
|
|
816
815
|
## Curve Generator
|
|
817
816
|
|
|
817
|
+
The visualization of the curve generators has not been implemented in current version. They can be visualized in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1).
|
|
818
|
+
|
|
818
819
|
|Generator|2D|3D|
|
|
819
820
|
| ------- | -------------------------------------------------------- | --------------------------------------------------------
|
|
820
|
-
| **Polynomia** | |Not implemented
|
|
822
|
+
| **Bezier** ||Not implemented
|
|
823
|
+
| **Cubic Spline** ||Not implemented
|
|
824
|
+
| **BSpline** ||Not implemented
|
|
825
|
+
| **Dubins** ||Not implemented
|
|
826
|
+
| **Reeds-Shepp** ||Not implemented
|
|
827
|
+
| **Fem-Pos Smoother** ||Not implemented
|
|
826
828
|
|
|
827
829
|
# Future Works
|
|
828
830
|
|
|
@@ -832,8 +834,6 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
832
834
|
|
|
833
835
|
* Path planning on topological map.
|
|
834
836
|
|
|
835
|
-
* Sample search with Dubins or Reeds-Shepp curves.
|
|
836
|
-
|
|
837
837
|
* Application on ROS2.
|
|
838
838
|
|
|
839
839
|
* Application in mainstream robot simulation environments (e.g. Gazebo, Carla, Airsim, PyBullet, MuJoCo, Issac Sim).
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
# Introduction
|
|
3
3
|
|
|
4
|
-
`Python Motion Planning` repository provides the implementations of common `Motion planning` algorithms, including path planners on N-D grid, controllers for path-tracking, curve generators, a visualizer based on matplotlib and a toy physical simulator to test controllers.
|
|
5
|
-
|
|
6
4
|
`Motion planning` plans the state sequence of the robot without conflict between the start and goal.
|
|
7
5
|
|
|
8
6
|
`Motion planning` mainly includes `Path planning` and `Trajectory planning`.
|
|
@@ -10,6 +8,8 @@
|
|
|
10
8
|
* `Path Planning`: It's based on path constraints (such as obstacles), planning the optimal path sequence for the robot to travel without conflict between the start and goal.
|
|
11
9
|
* `Trajectory planning`: It plans the motion state to approach the global path based on kinematics, dynamics constraints and path sequence.
|
|
12
10
|
|
|
11
|
+
This repository provides the implementations of common `Motion planning` algorithms, including path planners on N-D grid and controllers for path-tracking, a visualizer based on matplotlib and a toy physical simulator to test controllers.
|
|
12
|
+
|
|
13
13
|
The theory analysis can be found at [motion-planning](https://blog.csdn.net/frigidwinter/category_11410243.html).
|
|
14
14
|
|
|
15
15
|
We also provide [ROS C++](https://github.com/ai-winter/ros_motion_planning) version and [Matlab](https://github.com/ai-winter/matlab_motion_planning) version.
|
|
@@ -36,8 +36,7 @@ python_motion_planning
|
|
|
36
36
|
| ├─graph_search
|
|
37
37
|
| ├─sample_search
|
|
38
38
|
| └─hybrid_search
|
|
39
|
-
└─
|
|
40
|
-
| └─curve_generator
|
|
39
|
+
└─curve_generator
|
|
41
40
|
```
|
|
42
41
|
|
|
43
42
|
## Install
|
|
@@ -51,7 +50,7 @@ conda activate pmp
|
|
|
51
50
|
To install the repository, please run the following command in shell.
|
|
52
51
|
|
|
53
52
|
```shell
|
|
54
|
-
pip install python-motion-planning
|
|
53
|
+
pip install python-motion-planning==2.0.dev2
|
|
55
54
|
```
|
|
56
55
|
|
|
57
56
|
## Run
|
|
@@ -108,7 +107,7 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
108
107
|
| **PID** ||Not implemented
|
|
109
108
|
| **APF** ||Not implemented
|
|
110
109
|
| **DWA** ||Not implemented
|
|
111
|
-
| **RPP**
|
|
110
|
+
| **RPP** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
112
111
|
| **LQR** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
113
112
|
| **MPC** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
114
113
|
| **MPPI** |Not implemented|Not implemented
|
|
@@ -119,14 +118,17 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
119
118
|
|
|
120
119
|
## Curve Generator
|
|
121
120
|
|
|
121
|
+
The visualization of the curve generators has not been implemented in current version. They can be visualized in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1).
|
|
122
|
+
|
|
122
123
|
|Generator|2D|3D|
|
|
123
124
|
| ------- | -------------------------------------------------------- | --------------------------------------------------------
|
|
124
|
-
| **Polynomia** | |Not implemented
|
|
126
|
+
| **Bezier** ||Not implemented
|
|
127
|
+
| **Cubic Spline** ||Not implemented
|
|
128
|
+
| **BSpline** ||Not implemented
|
|
129
|
+
| **Dubins** ||Not implemented
|
|
130
|
+
| **Reeds-Shepp** ||Not implemented
|
|
131
|
+
| **Fem-Pos Smoother** ||Not implemented
|
|
130
132
|
|
|
131
133
|
# Future Works
|
|
132
134
|
|
|
@@ -136,8 +138,6 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
136
138
|
|
|
137
139
|
* Path planning on topological map.
|
|
138
140
|
|
|
139
|
-
* Sample search with Dubins or Reeds-Shepp curves.
|
|
140
|
-
|
|
141
141
|
* Application on ROS2.
|
|
142
142
|
|
|
143
143
|
* Application in mainstream robot simulation environments (e.g. Gazebo, Carla, Airsim, PyBullet, MuJoCo, Issac Sim).
|
|
@@ -35,31 +35,42 @@ class Geometry:
|
|
|
35
35
|
else:
|
|
36
36
|
raise ValueError("Invalid distance type")
|
|
37
37
|
|
|
38
|
-
@staticmethod
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
# @staticmethod
|
|
39
|
+
# def angle(v1: tuple, v2: tuple) -> float:
|
|
40
|
+
# """
|
|
41
|
+
# Calculate the angle between two vectors
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
# Args:
|
|
44
|
+
# v1: First vector
|
|
45
|
+
# v2: Second vector
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
# Returns:
|
|
48
|
+
# angle_rad: Angle in rad between the two vectors
|
|
49
|
+
# """
|
|
50
|
+
# if len(v1) != len(v2):
|
|
51
|
+
# raise ValueError("Dimension mismatch")
|
|
52
|
+
|
|
53
|
+
# dot_product = sum(a * b for a, b in zip(v1, v2))
|
|
54
|
+
# v1_norm = math.sqrt(sum(a**2 for a in v1))
|
|
55
|
+
# v2_norm = math.sqrt(sum(b**2 for b in v2))
|
|
56
|
+
|
|
57
|
+
# if v1_norm == 0 or v2_norm == 0:
|
|
58
|
+
# raise ValueError("Zero vector cannot calculate angle")
|
|
59
|
+
|
|
60
|
+
# cos_theta = dot_product / (v1_norm * v2_norm)
|
|
61
|
+
|
|
62
|
+
# cos_theta = min(1.0, max(-1.0, cos_theta))
|
|
63
|
+
|
|
64
|
+
# angle_rad = math.acos(cos_theta)
|
|
65
|
+
|
|
66
|
+
# return angle_rad
|
|
50
67
|
|
|
51
68
|
@staticmethod
|
|
52
69
|
def regularize_orient(orient: np.ndarray) -> np.ndarray:
|
|
53
70
|
"""
|
|
54
71
|
Regularize orientation to be within (-pi, pi]
|
|
55
|
-
|
|
56
|
-
Args:
|
|
57
|
-
orient: the orientation angle
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
new_orient: regularized orientation
|
|
61
72
|
"""
|
|
62
|
-
return
|
|
73
|
+
return np.mod(orient + np.pi, 2 * np.pi) - np.pi
|
|
63
74
|
|
|
64
75
|
@staticmethod
|
|
65
76
|
def add_orient_to_2d_path(path: List[Tuple[float, float]]) -> List[Tuple[float, float, float]]:
|
|
@@ -91,4 +102,4 @@ class Geometry:
|
|
|
91
102
|
last_x, last_y = path[-1]
|
|
92
103
|
path_with_orient.append((last_x, last_y, path_with_orient[-1][2]))
|
|
93
104
|
|
|
94
|
-
return path_with_orient
|
|
105
|
+
return path_with_orient
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .polynomial_curve import Polynomial
|
|
2
|
+
from .bezier_curve import Bezier
|
|
3
|
+
from .bspline_curve import BSpline
|
|
4
|
+
from .dubins_curve import Dubins
|
|
5
|
+
from .reeds_shepp import ReedsShepp
|
|
6
|
+
from .cubic_spline import CubicSpline
|
|
7
|
+
from .fem_pos_smooth import FemPosSmoother
|
|
8
|
+
|
|
9
|
+
__all__ = ["Polynomial", "Dubins", "ReedsShepp", "Bezier", "CubicSpline", "BSpline", "FemPosSmoother"]
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@file: bezier_curve.py
|
|
3
|
+
@breif: Bezier curve generation
|
|
4
|
+
@author: Winter
|
|
5
|
+
@update: 2023.7.25
|
|
6
|
+
"""
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from scipy.special import comb
|
|
10
|
+
# from python_motion_planning.utils import Plot
|
|
11
|
+
from .curve import Curve
|
|
12
|
+
|
|
13
|
+
class Bezier(Curve):
|
|
14
|
+
"""
|
|
15
|
+
Class for Bezier curve generation.
|
|
16
|
+
|
|
17
|
+
Parameters:
|
|
18
|
+
step (float): Simulation or interpolation size
|
|
19
|
+
offset (float): The offset of control points
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
>>> from python_motion_planning.curve_generation import Bezier
|
|
23
|
+
>>> points = [(0, 0, 0), (10, 10, -90), (20, 5, 60)]
|
|
24
|
+
>>> generator = Bezier(step, offset)
|
|
25
|
+
>>> generator.run(points)
|
|
26
|
+
"""
|
|
27
|
+
def __init__(self, step: float, offset: float) -> None:
|
|
28
|
+
super().__init__(step)
|
|
29
|
+
self.offset = offset
|
|
30
|
+
|
|
31
|
+
def __str__(self) -> str:
|
|
32
|
+
return "Bezier Curve"
|
|
33
|
+
|
|
34
|
+
def generation(self, start_pose: tuple, goal_pose: tuple):
|
|
35
|
+
"""
|
|
36
|
+
Generate the Bezier Curve.
|
|
37
|
+
|
|
38
|
+
Parameters:
|
|
39
|
+
start_pose (tuple): Initial pose (x, y, yaw)
|
|
40
|
+
goal_pose (tuple): Target pose (x, y, yaw)
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
x_list (list): x of the trajectory
|
|
44
|
+
y_list (list): y of the trajectory
|
|
45
|
+
yaw_list (list): yaw of the trajectory
|
|
46
|
+
"""
|
|
47
|
+
sx, sy, _ = start_pose
|
|
48
|
+
gx, gy, _ = goal_pose
|
|
49
|
+
n_points = int(np.hypot(sx - gx, sy - gy) / self.step)
|
|
50
|
+
control_points = self.getControlPoints(start_pose, goal_pose)
|
|
51
|
+
|
|
52
|
+
return [self.bezier(t, control_points) for t in np.linspace(0, 1, n_points)], \
|
|
53
|
+
control_points
|
|
54
|
+
|
|
55
|
+
def bezier(self, t: float, control_points: list) ->np.ndarray:
|
|
56
|
+
"""
|
|
57
|
+
Calculate the Bezier curve point.
|
|
58
|
+
|
|
59
|
+
Parameters:
|
|
60
|
+
t (float): scale factor
|
|
61
|
+
control_points (list[tuple]): control points
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
point (np.array): point in Bezier curve with t
|
|
65
|
+
"""
|
|
66
|
+
n = len(control_points) - 1
|
|
67
|
+
control_points = np.array(control_points)
|
|
68
|
+
return np.sum([comb(n, i) * t ** i * (1 - t) ** (n - i) *
|
|
69
|
+
control_points[i] for i in range(n + 1)], axis=0)
|
|
70
|
+
|
|
71
|
+
def getControlPoints(self, start_pose: tuple, goal_pose: tuple):
|
|
72
|
+
"""
|
|
73
|
+
Calculate control points heuristically.
|
|
74
|
+
|
|
75
|
+
Parameters:
|
|
76
|
+
start_pose (tuple): Initial pose (x, y, yaw)
|
|
77
|
+
goal_pose (tuple): Target pose (x, y, yaw)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
control_points (list[tuple]): Control points
|
|
81
|
+
"""
|
|
82
|
+
sx, sy, syaw = start_pose
|
|
83
|
+
gx, gy, gyaw = goal_pose
|
|
84
|
+
|
|
85
|
+
dist = np.hypot(sx - gx, sy - gy) / self.offset
|
|
86
|
+
return [(sx, sy),
|
|
87
|
+
(sx + dist * np.cos(syaw), sy + dist * np.sin(syaw)),
|
|
88
|
+
(gx - dist * np.cos(gyaw), gy - dist * np.sin(gyaw)),
|
|
89
|
+
(gx, gy)]
|
|
90
|
+
|
|
91
|
+
# def run(self, points: list):
|
|
92
|
+
# """
|
|
93
|
+
# Running both generation and animation.
|
|
94
|
+
|
|
95
|
+
# Parameters:
|
|
96
|
+
# points (list[tuple]): path points
|
|
97
|
+
# """
|
|
98
|
+
# assert len(points) >= 2, "Number of points should be at least 2."
|
|
99
|
+
# import matplotlib.pyplot as plt
|
|
100
|
+
|
|
101
|
+
# # generation
|
|
102
|
+
# path_x, path_y = [], []
|
|
103
|
+
# path_control_x, path_control_y = [], []
|
|
104
|
+
# for i in range(len(points) - 1):
|
|
105
|
+
# path, control_points = self.generation(
|
|
106
|
+
# (points[i][0], points[i][1], np.deg2rad(points[i][2])),
|
|
107
|
+
# (points[i + 1][0], points[i + 1][1], np.deg2rad(points[i + 1][2])))
|
|
108
|
+
|
|
109
|
+
# for pt in path:
|
|
110
|
+
# path_x.append(pt[0])
|
|
111
|
+
# path_y.append(pt[1])
|
|
112
|
+
|
|
113
|
+
# path_control_x.append(points[i][0])
|
|
114
|
+
# path_control_y.append(points[i][1])
|
|
115
|
+
|
|
116
|
+
# for pt in control_points:
|
|
117
|
+
# path_control_x.append(pt[0])
|
|
118
|
+
# path_control_y.append(pt[1])
|
|
119
|
+
|
|
120
|
+
# # animation
|
|
121
|
+
# plt.figure("curve generation")
|
|
122
|
+
# plt.plot(path_x, path_y, linewidth=2, c="#1f77b4")
|
|
123
|
+
# plt.plot(path_control_x, path_control_y, '--o', c='#dddddd', label="Control Points")
|
|
124
|
+
# for x, y, theta in points:
|
|
125
|
+
# Plot.plotArrow(x, y, np.deg2rad(theta), 2, 'blueviolet')
|
|
126
|
+
|
|
127
|
+
# plt.axis("equal")
|
|
128
|
+
# plt.legend()
|
|
129
|
+
# plt.title(str(self))
|
|
130
|
+
# plt.show()
|
|
131
|
+
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@file: bspline_curve.py
|
|
3
|
+
@breif: B-Spline curve generation
|
|
4
|
+
@author: Winter
|
|
5
|
+
@update: 2023.7.29
|
|
6
|
+
"""
|
|
7
|
+
import math
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from .curve import Curve
|
|
11
|
+
|
|
12
|
+
class BSpline(Curve):
|
|
13
|
+
"""
|
|
14
|
+
Class for B-Spline curve generation.
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
step (float): Simulation or interpolation size
|
|
18
|
+
k (int): Degree of curve
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
>>> from python_motion_planning.curve_generation import BSpline
|
|
22
|
+
>>> points = [(0, 0, 0), (10, 10, -90), (20, 5, 60)]
|
|
23
|
+
>>> generator = BSpline(step, k)
|
|
24
|
+
>>> generator.run(points)
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, step: float, k: int, param_mode: str="centripetal",
|
|
27
|
+
spline_mode: str="interpolation") -> None:
|
|
28
|
+
super().__init__(step)
|
|
29
|
+
self.k = k
|
|
30
|
+
|
|
31
|
+
assert param_mode == "centripetal" or param_mode == "chord_length" \
|
|
32
|
+
or param_mode == "uniform_spaced", "Parameter selection mode error!"
|
|
33
|
+
self.param_mode = param_mode
|
|
34
|
+
|
|
35
|
+
assert spline_mode == "interpolation" or spline_mode == "approximation", \
|
|
36
|
+
"Spline mode selection error!"
|
|
37
|
+
self.spline_mode = spline_mode
|
|
38
|
+
|
|
39
|
+
def __str__(self) -> str:
|
|
40
|
+
return "B-Spline Curve"
|
|
41
|
+
|
|
42
|
+
def baseFunction(self, i: int, k: int, t: float, knot: list):
|
|
43
|
+
"""
|
|
44
|
+
Calculate base function using Cox-deBoor function.
|
|
45
|
+
|
|
46
|
+
Parameters:
|
|
47
|
+
i (int): The index of base function
|
|
48
|
+
k (int): The degree of curve
|
|
49
|
+
t (float): parameter
|
|
50
|
+
knot (list[float]): knot vector
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Nik_t (float): The value of base function Nik(t)
|
|
54
|
+
"""
|
|
55
|
+
Nik_t = 0
|
|
56
|
+
if k == 0:
|
|
57
|
+
Nik_t = 1.0 if t >= knot[i] and t < knot[i + 1] else 0.0
|
|
58
|
+
else:
|
|
59
|
+
length1 = knot[i + k] - knot[i]
|
|
60
|
+
length2 = knot[i + k + 1] - knot[i + 1]
|
|
61
|
+
if not length1 and not length2:
|
|
62
|
+
Nik_t = 0
|
|
63
|
+
elif not length1:
|
|
64
|
+
Nik_t = (knot[i + k + 1] - t) / length2 * self.baseFunction(i + 1, k - 1, t, knot)
|
|
65
|
+
elif not length2:
|
|
66
|
+
Nik_t = (t - knot[i]) / length1 * self.baseFunction(i, k - 1, t, knot)
|
|
67
|
+
else:
|
|
68
|
+
Nik_t = (t - knot[i]) / length1 * self.baseFunction(i, k - 1, t, knot) + \
|
|
69
|
+
(knot[i + k + 1] - t) / length2 * self.baseFunction(i + 1, k - 1, t, knot)
|
|
70
|
+
return Nik_t
|
|
71
|
+
|
|
72
|
+
def paramSelection(self, points: list):
|
|
73
|
+
"""
|
|
74
|
+
Calculate parameters using the `uniform spaced` or `chrod length`
|
|
75
|
+
or `centripetal` method.
|
|
76
|
+
|
|
77
|
+
Parameters:
|
|
78
|
+
points (list[tuple]): path points
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Parameters (list[float]): The parameters of given points
|
|
82
|
+
"""
|
|
83
|
+
n = len(points)
|
|
84
|
+
x_list = [pt[0] for pt in points]
|
|
85
|
+
y_list = [pt[1] for pt in points]
|
|
86
|
+
dx, dy = np.diff(x_list), np.diff(y_list)
|
|
87
|
+
|
|
88
|
+
if self.param_mode == "uniform_spaced":
|
|
89
|
+
return np.linspace(0, 1, n).tolist()
|
|
90
|
+
|
|
91
|
+
elif self.param_mode == "chord_length":
|
|
92
|
+
parameters = np.zeros(n)
|
|
93
|
+
s = np.cumsum([math.hypot(idx, idy) for (idx, idy) in zip(dx, dy)])
|
|
94
|
+
for i in range(1, n):
|
|
95
|
+
parameters[i] = s[i - 1] / s[-1]
|
|
96
|
+
return parameters.tolist()
|
|
97
|
+
|
|
98
|
+
elif self.param_mode == "centripetal":
|
|
99
|
+
alpha = 0.5
|
|
100
|
+
s = np.cumsum([math.pow(math.hypot(idx, idy), alpha) for (idx, idy) in zip(dx, dy)])
|
|
101
|
+
parameters = np.zeros(n)
|
|
102
|
+
for i in range(1, n):
|
|
103
|
+
parameters[i] = s[i - 1] / s[-1]
|
|
104
|
+
return parameters.tolist()
|
|
105
|
+
|
|
106
|
+
def knotGeneration(self, param: list, n: int):
|
|
107
|
+
"""
|
|
108
|
+
Generate knot vector.
|
|
109
|
+
|
|
110
|
+
Parameters:
|
|
111
|
+
param (list[float]): The parameters of given points
|
|
112
|
+
n (int): The number of data points
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
knot (list[float]): The knot vector
|
|
116
|
+
"""
|
|
117
|
+
m = n + self.k + 1
|
|
118
|
+
knot = np.zeros(m)
|
|
119
|
+
for i in range(self.k + 1):
|
|
120
|
+
knot[i] = 0
|
|
121
|
+
for i in range(n, m):
|
|
122
|
+
knot[i] = 1
|
|
123
|
+
for i in range(self.k + 1, n):
|
|
124
|
+
for j in range(i - self.k, i):
|
|
125
|
+
knot[i] = knot[i] + param[j]
|
|
126
|
+
knot[i] = knot[i] / self.k
|
|
127
|
+
return knot.tolist()
|
|
128
|
+
|
|
129
|
+
def interpolation(self, points: list, param: list, knot: list):
|
|
130
|
+
"""
|
|
131
|
+
Given a set of N data points, D0, D1, ..., Dn and a degree k,
|
|
132
|
+
find a B-spline curve of degree k defined by N control points
|
|
133
|
+
that passes all data points in the given order.
|
|
134
|
+
|
|
135
|
+
Parameters:
|
|
136
|
+
points (list[tuple]): path points
|
|
137
|
+
param (list[float]): The parameters of given points
|
|
138
|
+
knot (list[float]): The knot vector
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
control_points (np.ndarray): The control points
|
|
142
|
+
"""
|
|
143
|
+
n = len(points)
|
|
144
|
+
N = np.zeros((n, n))
|
|
145
|
+
|
|
146
|
+
for i in range(n):
|
|
147
|
+
for j in range(n):
|
|
148
|
+
N[i][j] = self.baseFunction(j, self.k, param[i], knot)
|
|
149
|
+
N[n-1][n-1] = 1
|
|
150
|
+
N_inv = np.linalg.inv(N)
|
|
151
|
+
|
|
152
|
+
D = np.array(points)
|
|
153
|
+
|
|
154
|
+
return N_inv @ D
|
|
155
|
+
|
|
156
|
+
def approximation(self, points: list, param: list, knot: list):
|
|
157
|
+
"""
|
|
158
|
+
Given a set of N data points, D0, D1, ..., Dn, a degree k,
|
|
159
|
+
and a number H, where N > H > k >= 1, find a B-spline curve
|
|
160
|
+
of degree k defined by H control points that satisfies the
|
|
161
|
+
following conditions:
|
|
162
|
+
1. this curve contains the first and last data points;
|
|
163
|
+
2. this curve approximates the data polygon in the sense
|
|
164
|
+
of least square
|
|
165
|
+
|
|
166
|
+
Parameters:
|
|
167
|
+
points (list[tuple]): path points
|
|
168
|
+
param (list[float]): The parameters of given points
|
|
169
|
+
knot (list[float]): The knot vector
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
control_points (np.ndarray): The control points
|
|
173
|
+
"""
|
|
174
|
+
n = len(points)
|
|
175
|
+
D = np.array(points)
|
|
176
|
+
|
|
177
|
+
# heuristically setting the number of control points
|
|
178
|
+
h = n - 1
|
|
179
|
+
|
|
180
|
+
N = np.zeros((n, h))
|
|
181
|
+
for i in range(n):
|
|
182
|
+
for j in range(h):
|
|
183
|
+
N[i][j] = self.baseFunction(j, self.k, param[i], knot)
|
|
184
|
+
N_ = N[1 : n - 1, 1 : h - 1]
|
|
185
|
+
|
|
186
|
+
qk = np.zeros((n - 2, 2))
|
|
187
|
+
for i in range(1, n - 1):
|
|
188
|
+
qk[i - 1] = D[i, :] - N[i][0] * D[0, :] - N[i][h - 1] * D[-1, :]
|
|
189
|
+
Q = N_.T @ qk
|
|
190
|
+
|
|
191
|
+
P = np.linalg.inv(N_.T @ N_) @ Q
|
|
192
|
+
P = np.insert(P, 0, D[0, :], axis=0)
|
|
193
|
+
P = np.insert(P, len(P), D[-1, :], axis=0)
|
|
194
|
+
|
|
195
|
+
return P
|
|
196
|
+
|
|
197
|
+
def generation(self, t, k, knot, control_pts):
|
|
198
|
+
"""
|
|
199
|
+
Generate the B-spline curve.
|
|
200
|
+
|
|
201
|
+
Parameters:
|
|
202
|
+
t (np.ndarray): The parameter values
|
|
203
|
+
k (int): The degree of the B-spline curve
|
|
204
|
+
knot (list[float]): The knot vector
|
|
205
|
+
control_pts (np.ndarray): The control points
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
curve (np.ndarray): The B-spline curve
|
|
209
|
+
"""
|
|
210
|
+
N = np.zeros((len(t), len(control_pts)))
|
|
211
|
+
|
|
212
|
+
for i in range(len(t)):
|
|
213
|
+
for j in range(len(control_pts)):
|
|
214
|
+
N[i][j] = self.baseFunction(j, k, t[i], knot)
|
|
215
|
+
N[len(t) - 1][len(control_pts) - 1] = 1
|
|
216
|
+
|
|
217
|
+
return N @ control_pts
|
|
218
|
+
|
|
219
|
+
# def run(self, points: list, display: bool = True):
|
|
220
|
+
# """
|
|
221
|
+
# Running both generation and animation.
|
|
222
|
+
|
|
223
|
+
# Parameters:
|
|
224
|
+
# points (list[tuple]): path points
|
|
225
|
+
# """
|
|
226
|
+
# assert len(points) >= 2, "Number of points should be at least 2."
|
|
227
|
+
# import matplotlib.pyplot as plt
|
|
228
|
+
|
|
229
|
+
# if len(points[0]) > 2:
|
|
230
|
+
# points = [(points[i][0], points[i][1]) for i in range(len(points))]
|
|
231
|
+
|
|
232
|
+
# t = np.linspace(0, 1, int(1 / self.step))
|
|
233
|
+
# params = self.paramSelection(points)
|
|
234
|
+
# knot = self.knotGeneration(params, len(points))
|
|
235
|
+
|
|
236
|
+
# if self.spline_mode == "interpolation":
|
|
237
|
+
# control_pts = self.interpolation(points, params, knot)
|
|
238
|
+
# elif self.spline_mode == "approximation":
|
|
239
|
+
# control_pts = self.approximation(points, params, knot)
|
|
240
|
+
# h = len(control_pts)
|
|
241
|
+
# new_points = [(control_pts[i][0], control_pts[i][1])
|
|
242
|
+
# for i in range(h)]
|
|
243
|
+
# params = self.paramSelection(new_points)
|
|
244
|
+
# knot = self.knotGeneration(params, h)
|
|
245
|
+
# else:
|
|
246
|
+
# raise NotImplementedError
|
|
247
|
+
|
|
248
|
+
# control_x = control_pts[:, 0].tolist()
|
|
249
|
+
# control_y = control_pts[:, 1].tolist()
|
|
250
|
+
|
|
251
|
+
# path = self.generation(t, self.k, knot, control_pts)
|
|
252
|
+
# path_x = path[:, 0].tolist()
|
|
253
|
+
# path_y = path[:, 1].tolist()
|
|
254
|
+
|
|
255
|
+
# if display:
|
|
256
|
+
# # animation
|
|
257
|
+
# plt.figure("curve generation")
|
|
258
|
+
|
|
259
|
+
# # static
|
|
260
|
+
# plt.figure("curve generation")
|
|
261
|
+
# plt.plot(path_x, path_y, linewidth=2, c="#1f77b4")
|
|
262
|
+
# plt.plot(control_x, control_y, '--o', c='#dddddd', label="Control Points")
|
|
263
|
+
# for x, y in points:
|
|
264
|
+
# plt.plot(x, y, "xr", linewidth=2)
|
|
265
|
+
# plt.axis("equal")
|
|
266
|
+
# plt.legend()
|
|
267
|
+
# plt.title(str(self))
|
|
268
|
+
|
|
269
|
+
# plt.show()
|
|
270
|
+
|
|
271
|
+
# return [(ix, iy) for (ix, iy) in zip(path_x, path_y)]
|