python-motion-planning 2.0.dev2__py3-none-any.whl → 2.0.1__py3-none-any.whl
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/__init__.py +1 -1
- python_motion_planning/common/env/map/grid.py +394 -129
- python_motion_planning/common/utils/geometry.py +18 -29
- python_motion_planning/path_planner/sample_search/rrt.py +5 -5
- python_motion_planning/path_planner/sample_search/rrt_connect.py +2 -2
- python_motion_planning/path_planner/sample_search/rrt_star.py +31 -11
- python_motion_planning/traj_optimizer/__init__.py +2 -0
- python_motion_planning/traj_optimizer/base_curve_generator.py +53 -0
- python_motion_planning/traj_optimizer/curve_generator/__init__.py +2 -0
- python_motion_planning/traj_optimizer/curve_generator/point_based/__init__.py +2 -0
- python_motion_planning/traj_optimizer/curve_generator/point_based/bspline.py +256 -0
- python_motion_planning/traj_optimizer/curve_generator/point_based/cubic_spline.py +115 -0
- python_motion_planning/traj_optimizer/curve_generator/pose_based/__init__.py +4 -0
- python_motion_planning/traj_optimizer/curve_generator/pose_based/bezier.py +121 -0
- python_motion_planning/traj_optimizer/curve_generator/pose_based/dubins.py +355 -0
- python_motion_planning/traj_optimizer/curve_generator/pose_based/polynomial.py +197 -0
- python_motion_planning/traj_optimizer/curve_generator/pose_based/reeds_shepp.py +606 -0
- {python_motion_planning-2.0.dev2.dist-info → python_motion_planning-2.0.1.dist-info}/METADATA +22 -15
- {python_motion_planning-2.0.dev2.dist-info → python_motion_planning-2.0.1.dist-info}/RECORD +22 -20
- {python_motion_planning-2.0.dev2.dist-info → python_motion_planning-2.0.1.dist-info}/WHEEL +1 -1
- python_motion_planning/curve_generator/__init__.py +0 -9
- python_motion_planning/curve_generator/bezier_curve.py +0 -131
- python_motion_planning/curve_generator/bspline_curve.py +0 -271
- python_motion_planning/curve_generator/cubic_spline.py +0 -128
- python_motion_planning/curve_generator/curve.py +0 -64
- python_motion_planning/curve_generator/dubins_curve.py +0 -348
- python_motion_planning/curve_generator/fem_pos_smooth.py +0 -114
- python_motion_planning/curve_generator/polynomial_curve.py +0 -226
- python_motion_planning/curve_generator/reeds_shepp.py +0 -736
- {python_motion_planning-2.0.dev2.dist-info → python_motion_planning-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {python_motion_planning-2.0.dev2.dist-info → python_motion_planning-2.0.1.dist-info}/top_level.txt +0 -0
{python_motion_planning-2.0.dev2.dist-info → python_motion_planning-2.0.1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-motion-planning
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
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
|
|
@@ -685,6 +685,7 @@ Requires-Python: >=3.6
|
|
|
685
685
|
Description-Content-Type: text/markdown
|
|
686
686
|
License-File: LICENSE
|
|
687
687
|
Requires-Dist: numpy
|
|
688
|
+
Requires-Dist: numba
|
|
688
689
|
Requires-Dist: scipy
|
|
689
690
|
Requires-Dist: matplotlib
|
|
690
691
|
Requires-Dist: osqp
|
|
@@ -697,6 +698,8 @@ Dynamic: license-file
|
|
|
697
698
|
|
|
698
699
|
# Introduction
|
|
699
700
|
|
|
701
|
+
`Python Motion Planning` repository provides the implementations of common `Motion planning` algorithms, including path planners on N-D grid, controllers for path-tracking, trajectory optimizers, a visualizer based on matplotlib and a toy physical simulator to test controllers.
|
|
702
|
+
|
|
700
703
|
`Motion planning` plans the state sequence of the robot without conflict between the start and goal.
|
|
701
704
|
|
|
702
705
|
`Motion planning` mainly includes `Path planning` and `Trajectory planning`.
|
|
@@ -704,8 +707,6 @@ Dynamic: license-file
|
|
|
704
707
|
* `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.
|
|
705
708
|
* `Trajectory planning`: It plans the motion state to approach the global path based on kinematics, dynamics constraints and path sequence.
|
|
706
709
|
|
|
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
710
|
The theory analysis can be found at [motion-planning](https://blog.csdn.net/frigidwinter/category_11410243.html).
|
|
710
711
|
|
|
711
712
|
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,7 +733,8 @@ python_motion_planning
|
|
|
732
733
|
| ├─graph_search
|
|
733
734
|
| ├─sample_search
|
|
734
735
|
| └─hybrid_search
|
|
735
|
-
└─
|
|
736
|
+
└─traj_optimizer
|
|
737
|
+
└─curve_generator
|
|
736
738
|
```
|
|
737
739
|
|
|
738
740
|
## Install
|
|
@@ -746,7 +748,7 @@ conda activate pmp
|
|
|
746
748
|
To install the repository, please run the following command in shell.
|
|
747
749
|
|
|
748
750
|
```shell
|
|
749
|
-
pip install python-motion-planning
|
|
751
|
+
pip install python-motion-planning
|
|
750
752
|
```
|
|
751
753
|
|
|
752
754
|
## Run
|
|
@@ -803,7 +805,7 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
803
805
|
| **PID** ||Not implemented
|
|
804
806
|
| **APF** ||Not implemented
|
|
805
807
|
| **DWA** ||Not implemented
|
|
806
|
-
| **RPP**
|
|
808
|
+
| **RPP** ||Not implemented
|
|
807
809
|
| **LQR** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
808
810
|
| **MPC** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
809
811
|
| **MPPI** |Not implemented|Not implemented
|
|
@@ -812,19 +814,22 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
812
814
|
| **DQN** |Not implemented|Not implemented
|
|
813
815
|
| **DDPG** |Implemented in [V1.0](https://github.com/ai-winter/python_motion_planning/tree/v1.0), not migrated|Not implemented
|
|
814
816
|
|
|
815
|
-
##
|
|
817
|
+
## Trajectory Optimizer
|
|
818
|
+
### Curve Generator
|
|
819
|
+
#### Point-based
|
|
816
820
|
|
|
817
|
-
|
|
821
|
+
|Generator|2D|3D|
|
|
822
|
+
| ------- | -------------------------------------------------------- | --------------------------------------------------------
|
|
823
|
+
| **Cubic Spline** ||Not implemented
|
|
824
|
+
| **BSpline** ||Not implemented
|
|
818
825
|
|
|
826
|
+
#### Pose-based
|
|
819
827
|
|Generator|2D|3D|
|
|
820
828
|
| ------- | -------------------------------------------------------- | --------------------------------------------------------
|
|
821
|
-
| **Polynomia** | |Not implemented
|
|
826
|
-
| **Reeds-Shepp** ||Not implemented
|
|
827
|
-
| **Fem-Pos Smoother** ||Not implemented
|
|
829
|
+
| **Polynomia** | |Not implemented
|
|
830
|
+
| **Bezier** ||Not implemented
|
|
831
|
+
| **Dubins** ||Not implemented
|
|
832
|
+
| **Reeds-Shepp** ||Not implemented
|
|
828
833
|
|
|
829
834
|
# Future Works
|
|
830
835
|
|
|
@@ -834,6 +839,8 @@ The visualization of the curve generators has not been implemented in current ve
|
|
|
834
839
|
|
|
835
840
|
* Path planning on topological map.
|
|
836
841
|
|
|
842
|
+
* Sample search with Dubins or Reeds-Shepp curves.
|
|
843
|
+
|
|
837
844
|
* Application on ROS2.
|
|
838
845
|
|
|
839
846
|
* Application in mainstream robot simulation environments (e.g. Gazebo, Carla, Airsim, PyBullet, MuJoCo, Issac Sim).
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
python_motion_planning/__init__.py,sha256=
|
|
1
|
+
python_motion_planning/__init__.py,sha256=qsRVlO3n-WSdeyH6NvduCQJ_G0Yqrml7F_juvs2UnJ4,108
|
|
2
2
|
python_motion_planning/common/__init__.py,sha256=9CeruPgGOBOtro9EafPEhK5VKTav2OWeNbMLJCBwuNg,67
|
|
3
3
|
python_motion_planning/common/env/__init__.py,sha256=Q8qIUcn5fvtLrmrc3SXStQoEwwrNMF-IofKotFermBk,129
|
|
4
4
|
python_motion_planning/common/env/node.py,sha256=6I10JpU4tjK4aZEMWN7Dttz41QKskNFoe7gBR4aSyII,2727
|
|
5
5
|
python_motion_planning/common/env/types.py,sha256=h5HtPrffu5qH_F1G4V1g8eXBPTPuDW-nFFfEFECVGYo,380
|
|
6
6
|
python_motion_planning/common/env/map/__init__.py,sha256=5bVsJd2mrghKMj7erXfgc8V4NahXHe6zXngG9fMCjo0,44
|
|
7
7
|
python_motion_planning/common/env/map/base_map.py,sha256=tX-9iO3RwbdvhGUHDtPNQUj8h-HNONjopXCLyUdtfQE,3321
|
|
8
|
-
python_motion_planning/common/env/map/grid.py,sha256
|
|
8
|
+
python_motion_planning/common/env/map/grid.py,sha256=-QDhKpKrjE4Hi-NZPWIgPiiZagJCZH_dw8QgpHgLor4,28441
|
|
9
9
|
python_motion_planning/common/env/robot/__init__.py,sha256=njq1_k2uWikGH2AjtxoFDdmxqsM1YY5B9nVtIheyx6Y,122
|
|
10
10
|
python_motion_planning/common/env/robot/base_robot.py,sha256=KEajU9iFCnrzDOFp3Vm3SMWJWQgGJAYLT4VB6IMX2Is,7913
|
|
11
11
|
python_motion_planning/common/env/robot/circular_robot.py,sha256=6SS3XP91WfQlccxbtyVLjmPQjgesP9cFaxXg6txkxVI,1512
|
|
@@ -16,7 +16,7 @@ python_motion_planning/common/env/world/toy_simulator.py,sha256=J2JrZhQD-lCd4TB2
|
|
|
16
16
|
python_motion_planning/common/utils/__init__.py,sha256=wYzKTiyKgYfl5cTO0pUHF1zkr8Q9VhhEwKcRy1xSSdM,114
|
|
17
17
|
python_motion_planning/common/utils/child_tree.py,sha256=f6ypaZ-d7mJpWOaVH99KriJuzjDc6q353USsO7D5F9g,625
|
|
18
18
|
python_motion_planning/common/utils/frame_transformer.py,sha256=D9xaOUcxCPLvTl9oJHRSuhue84i88nMiuI-3ns0i7Ao,7609
|
|
19
|
-
python_motion_planning/common/utils/geometry.py,sha256=
|
|
19
|
+
python_motion_planning/common/utils/geometry.py,sha256=FFYM_eVAgJ3wA7H8MRXNvwXliGd6dKo4WU8fzbwdCXE,2693
|
|
20
20
|
python_motion_planning/common/visualizer/__init__.py,sha256=HWWbLehtqEl0q_hEO28tEMDH-v8lXqduN-EJ7mo9LEI,90
|
|
21
21
|
python_motion_planning/common/visualizer/base_visualizer.py,sha256=sjkH8lbyW8q9BVIEaQBTF10M27d73cpQqdTAPbEBFD0,5518
|
|
22
22
|
python_motion_planning/common/visualizer/visualizer_2d.py,sha256=mqaKFZEtNHOCm82I1nCbCOhDP444JSySq1BzQCnPyEM,15656
|
|
@@ -31,15 +31,6 @@ python_motion_planning/controller/path_tracker/path_tracker.py,sha256=5p_MhqRWpM
|
|
|
31
31
|
python_motion_planning/controller/path_tracker/pid.py,sha256=pqZggmTWaNd7XrlqfaK4wtBk9syg8PnIC7vOEnfN9S8,2403
|
|
32
32
|
python_motion_planning/controller/path_tracker/pure_pursuit.py,sha256=gsfiMXZx3RwHIwmI2CSu4fTZNFKbZP31cXMgKUdDjs8,2405
|
|
33
33
|
python_motion_planning/controller/path_tracker/rpp.py,sha256=e7qRIaUfeiVfVoiY5k797Yk9RK-Q7gnegmaOB7_BVP4,4181
|
|
34
|
-
python_motion_planning/curve_generator/__init__.py,sha256=6eeN0NBlAndBhjk-ol3Yaa-0om2lNG7n43BASRfeV9k,370
|
|
35
|
-
python_motion_planning/curve_generator/bezier_curve.py,sha256=E0J4bBxVaYZCRViKG4kEcZn9Scua0AJlrh-_RiycpSw,3705
|
|
36
|
-
python_motion_planning/curve_generator/bspline_curve.py,sha256=bUDIOcCYgKgfznMwEL_TQQ82sTUlB_sOFZhi3hAw0FQ,9418
|
|
37
|
-
python_motion_planning/curve_generator/cubic_spline.py,sha256=S5p3uNWDTgHR6JqLEMDEnr9A3A0KjyqH0aNBCQVmVFw,3452
|
|
38
|
-
python_motion_planning/curve_generator/curve.py,sha256=xf7G5lDGTCVUBoSK8Oa14fmdf_AANOZVqdSmAKlwu-A,1543
|
|
39
|
-
python_motion_planning/curve_generator/dubins_curve.py,sha256=EPKF7gRZT-Omc88RWmrDfQzGBzFZzxqzmdlemMBfnLM,11041
|
|
40
|
-
python_motion_planning/curve_generator/fem_pos_smooth.py,sha256=8K2OI6YBP40T9zXp6uXdQ8dggLqHdsR9VXoqP_-hawk,3512
|
|
41
|
-
python_motion_planning/curve_generator/polynomial_curve.py,sha256=h247Zk23ae-n3lQqZuWBp-rNs7eDBNJSD_hGtQmr69s,7602
|
|
42
|
-
python_motion_planning/curve_generator/reeds_shepp.py,sha256=_-0_fo85vwmQVfBvsZ3-MzK96gAzzKn-kSwwskW8JIk,21511
|
|
43
34
|
python_motion_planning/path_planner/__init__.py,sha256=Y0Im0cJ3iuUOYJyAOYvA_IavaNTNowb7SE6atrdJqX0,121
|
|
44
35
|
python_motion_planning/path_planner/base_path_planner.py,sha256=YZcLqAIkLJtp5MWoT5zPmzxv05xUlnDpfuzN-CgPQuc,3640
|
|
45
36
|
python_motion_planning/path_planner/graph_search/__init__.py,sha256=ugZpHV12dY-yb8d1jx4NepdRzQKn2qNKS6yWEBlvWy0,146
|
|
@@ -52,11 +43,22 @@ python_motion_planning/path_planner/graph_search/theta_star.py,sha256=JxxWukRTI4
|
|
|
52
43
|
python_motion_planning/path_planner/hybrid_search/__init__.py,sha256=RCvNhSq6nskZPCc7jo9Y5MOzrD4f7TL9RfVUCHgpeq4,30
|
|
53
44
|
python_motion_planning/path_planner/hybrid_search/voronoi_planner.py,sha256=sDTE-IFMf2035mUIRulEIOF0NiZSrwhW_bWrCiPetu4,7897
|
|
54
45
|
python_motion_planning/path_planner/sample_search/__init__.py,sha256=RYz6o_xmdsoErMGdBKvXEK4w-48P_ogi1bJsdJmUupk,71
|
|
55
|
-
python_motion_planning/path_planner/sample_search/rrt.py,sha256=
|
|
56
|
-
python_motion_planning/path_planner/sample_search/rrt_connect.py,sha256=
|
|
57
|
-
python_motion_planning/path_planner/sample_search/rrt_star.py,sha256=
|
|
58
|
-
python_motion_planning
|
|
59
|
-
python_motion_planning
|
|
60
|
-
python_motion_planning
|
|
61
|
-
python_motion_planning
|
|
62
|
-
python_motion_planning
|
|
46
|
+
python_motion_planning/path_planner/sample_search/rrt.py,sha256=hFBN1RaAnBn_ap7V2IPdkkKJIaMEIc7bHGALxoMkV-I,8682
|
|
47
|
+
python_motion_planning/path_planner/sample_search/rrt_connect.py,sha256=2GYQS5InB-jWr74c_dDGnLLCkIIeLnIrJmgfBfNNtOw,9670
|
|
48
|
+
python_motion_planning/path_planner/sample_search/rrt_star.py,sha256=f32G0h3_ds0cWvukNDRtDUoLZy0_KYpALcqCQcTxP1w,11223
|
|
49
|
+
python_motion_planning/traj_optimizer/__init__.py,sha256=0HeRril2pkNw1uUdro2HuV5z3eouQaC-kh6_uHOTzZg,69
|
|
50
|
+
python_motion_planning/traj_optimizer/base_curve_generator.py,sha256=m7-EZOIH5lOFiMVyvh5LYemjnWsiw0yRAvYUWG5mIFQ,1619
|
|
51
|
+
python_motion_planning/traj_optimizer/curve_generator/__init__.py,sha256=q40AJi09Wgv84NEU7fkdcSdNIGwoKy42Bsnt7YHaOdY,55
|
|
52
|
+
python_motion_planning/traj_optimizer/curve_generator/point_based/__init__.py,sha256=3V3ddQ0RfWs9oS57MUioGqzmMhPEXdVxbHkL9t_KlSM,53
|
|
53
|
+
python_motion_planning/traj_optimizer/curve_generator/point_based/bspline.py,sha256=GRcRHCC56Kdm74LFv96ANzHdaBxihTCfL-sk87rD3h8,9110
|
|
54
|
+
python_motion_planning/traj_optimizer/curve_generator/point_based/cubic_spline.py,sha256=sArmL1kLKHc-NRLFtczwpO6ATmuI3SB_FHTgSk826wI,3962
|
|
55
|
+
python_motion_planning/traj_optimizer/curve_generator/pose_based/__init__.py,sha256=muLe-_uENMf_btwqmVsRP0Ikbryut3Wl0_0BxNRhhbU,101
|
|
56
|
+
python_motion_planning/traj_optimizer/curve_generator/pose_based/bezier.py,sha256=BuLp6MzbyhuElD4qnos_nQQi9HvRVxx2AI5xPuUf2_I,4405
|
|
57
|
+
python_motion_planning/traj_optimizer/curve_generator/pose_based/dubins.py,sha256=76ujAOJHl3o4HkV1e5wuZEyz9wxzaGkDizDUx3M9C0w,13895
|
|
58
|
+
python_motion_planning/traj_optimizer/curve_generator/pose_based/polynomial.py,sha256=kjDkVskkfFHERZdJx6GU_GrRTJmrGHuX383W2s1oECI,7381
|
|
59
|
+
python_motion_planning/traj_optimizer/curve_generator/pose_based/reeds_shepp.py,sha256=I6KjYZvG4lOE2N9_vp1hSzJuan4SOrpuQF2L57owII4,22970
|
|
60
|
+
python_motion_planning-2.0.1.dist-info/licenses/LICENSE,sha256=a4N8el8H0UrdAJzCeVgj9HklpT3VkZfsy4aL1SAifJE,35793
|
|
61
|
+
python_motion_planning-2.0.1.dist-info/METADATA,sha256=61r3x6QoQCBJIHm1yt10khJLLdTw5P7zEXHZGkZwr7Y,49587
|
|
62
|
+
python_motion_planning-2.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
63
|
+
python_motion_planning-2.0.1.dist-info/top_level.txt,sha256=VtZTYZios8VncYIkec7tOVdYqj5oMRmoeBb9RcJHluY,23
|
|
64
|
+
python_motion_planning-2.0.1.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
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"]
|
|
@@ -1,131 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,271 +0,0 @@
|
|
|
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)]
|