python-motion-planning 2.0.dev1__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/base_map.py +2 -8
- python_motion_planning/common/env/map/grid.py +456 -198
- python_motion_planning/common/utils/__init__.py +2 -1
- python_motion_planning/common/utils/child_tree.py +22 -0
- python_motion_planning/common/utils/geometry.py +18 -29
- python_motion_planning/common/visualizer/__init__.py +3 -1
- python_motion_planning/common/visualizer/base_visualizer.py +165 -0
- python_motion_planning/common/visualizer/{visualizer.py → visualizer_2d.py} +97 -220
- python_motion_planning/common/visualizer/visualizer_3d.py +242 -0
- python_motion_planning/controller/base_controller.py +37 -4
- python_motion_planning/controller/path_tracker/__init__.py +2 -1
- python_motion_planning/controller/path_tracker/apf.py +22 -23
- python_motion_planning/controller/path_tracker/dwa.py +14 -17
- python_motion_planning/controller/path_tracker/path_tracker.py +4 -1
- python_motion_planning/controller/path_tracker/pid.py +7 -1
- python_motion_planning/controller/path_tracker/pure_pursuit.py +7 -1
- python_motion_planning/controller/path_tracker/rpp.py +111 -0
- python_motion_planning/path_planner/__init__.py +2 -1
- python_motion_planning/path_planner/base_path_planner.py +45 -11
- python_motion_planning/path_planner/graph_search/__init__.py +4 -1
- python_motion_planning/path_planner/graph_search/a_star.py +12 -14
- python_motion_planning/path_planner/graph_search/dijkstra.py +15 -15
- python_motion_planning/path_planner/graph_search/gbfs.py +100 -0
- python_motion_planning/path_planner/graph_search/jps.py +199 -0
- python_motion_planning/path_planner/graph_search/lazy_theta_star.py +113 -0
- python_motion_planning/path_planner/graph_search/theta_star.py +17 -19
- python_motion_planning/path_planner/hybrid_search/__init__.py +1 -0
- python_motion_planning/path_planner/hybrid_search/voronoi_planner.py +204 -0
- python_motion_planning/path_planner/sample_search/__init__.py +2 -1
- python_motion_planning/path_planner/sample_search/rrt.py +73 -31
- python_motion_planning/path_planner/sample_search/rrt_connect.py +237 -0
- python_motion_planning/path_planner/sample_search/rrt_star.py +220 -150
- 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.dev1.dist-info → python_motion_planning-2.0.1.dist-info}/METADATA +71 -29
- python_motion_planning-2.0.1.dist-info/RECORD +64 -0
- {python_motion_planning-2.0.dev1.dist-info → python_motion_planning-2.0.1.dist-info}/WHEEL +1 -1
- python_motion_planning/common/env/robot/tmp.py +0 -404
- 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.dev1.dist-info/RECORD +0 -53
- {python_motion_planning-2.0.dev1.dist-info → python_motion_planning-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {python_motion_planning-2.0.dev1.dist-info → python_motion_planning-2.0.1.dist-info}/top_level.txt +0 -0
{python_motion_planning-2.0.dev1.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,15 +685,21 @@ 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
|
|
691
692
|
Requires-Dist: gymnasium
|
|
693
|
+
Requires-Dist: faiss-cpu
|
|
694
|
+
Requires-Dist: pyvista
|
|
695
|
+
Requires-Dist: pyvistaqt
|
|
692
696
|
Dynamic: license-file
|
|
693
697
|
|
|
694
698
|
|
|
695
699
|
# Introduction
|
|
696
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
|
+
|
|
697
703
|
`Motion planning` plans the state sequence of the robot without conflict between the start and goal.
|
|
698
704
|
|
|
699
705
|
`Motion planning` mainly includes `Path planning` and `Trajectory planning`.
|
|
@@ -705,7 +711,7 @@ The theory analysis can be found at [motion-planning](https://blog.csdn.net/frig
|
|
|
705
711
|
|
|
706
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.
|
|
707
713
|
|
|
708
|
-
|
|
714
|
+
**Your stars and forks are welcome!**
|
|
709
715
|
|
|
710
716
|
# Quick Start
|
|
711
717
|
|
|
@@ -725,8 +731,10 @@ python_motion_planning
|
|
|
725
731
|
| └─path_tracker
|
|
726
732
|
├─path_planner
|
|
727
733
|
| ├─graph_search
|
|
728
|
-
|
|
|
729
|
-
└─
|
|
734
|
+
| ├─sample_search
|
|
735
|
+
| └─hybrid_search
|
|
736
|
+
└─traj_optimizer
|
|
737
|
+
└─curve_generator
|
|
730
738
|
```
|
|
731
739
|
|
|
732
740
|
## Install
|
|
@@ -740,7 +748,7 @@ conda activate pmp
|
|
|
740
748
|
To install the repository, please run the following command in shell.
|
|
741
749
|
|
|
742
750
|
```shell
|
|
743
|
-
pip install python-motion-planning
|
|
751
|
+
pip install python-motion-planning
|
|
744
752
|
```
|
|
745
753
|
|
|
746
754
|
## Run
|
|
@@ -749,29 +757,40 @@ Please refer to the Tutorials part of [online documentation](https://ai-winter.g
|
|
|
749
757
|
|
|
750
758
|
# Demos
|
|
751
759
|
## Path Planner
|
|
752
|
-
|
|
760
|
+
### Graph Search
|
|
753
761
|
|Planner|2D Grid|3D Grid
|
|
754
762
|
|-------|-------|-------
|
|
755
|
-
**
|
|
756
|
-
**
|
|
757
|
-
**A\***|||
|
|
764
|
+
**GBFS**||
|
|
765
|
+
**A\***||
|
|
766
|
+
**JPS**||
|
|
767
|
+
**Theta\***||
|
|
768
|
+
**Lazy Theta\***||
|
|
759
769
|
**D\***|Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
760
770
|
**LPA\***|Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
761
771
|
**D\* Lite**|Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
762
|
-
**Theta\***||
|
|
763
|
-
**Lazy Theta\***|Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
764
|
-
**S-Theta\***|Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
765
772
|
**Anya**|Not implemented|Not implemented
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
773
|
+
|
|
774
|
+
### Sample Search
|
|
775
|
+
|Planner|2D Grid|3D Grid
|
|
776
|
+
|-------|-------|-------
|
|
777
|
+
**RRT**||
|
|
778
|
+
**RRT\***||
|
|
779
|
+
**RRT-Connect**||
|
|
769
780
|
**Informed RRT**|Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
770
|
-
**
|
|
781
|
+
**PRM**|Not implemented|Not implemented
|
|
782
|
+
|
|
783
|
+
### Evolutionary Search
|
|
784
|
+
|Planner|2D Grid|3D Grid
|
|
785
|
+
|-------|-------|-------
|
|
771
786
|
| **ACO** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
772
787
|
| **GA** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
773
788
|
| **PSO** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
774
789
|
|
|
790
|
+
### Hybrid Search
|
|
791
|
+
|Planner|2D Grid|3D Grid
|
|
792
|
+
|-------|-------|-------
|
|
793
|
+
**Voronoi Planner**||
|
|
775
794
|
|
|
776
795
|
## Controller
|
|
777
796
|
|
|
@@ -779,14 +798,14 @@ We provide a toy simulator with simple physical simulation to test controllers (
|
|
|
779
798
|
|
|
780
799
|
In the following demos, the blue robot 1 is the `CircularRobot`, and the orange robot 2 is the `DiffDriveRobot`.
|
|
781
800
|
|
|
782
|
-
|
|
|
801
|
+
|Controller|2D|3D
|
|
783
802
|
|-------|-------|-------
|
|
784
803
|
|**Path Trakcer**||Not implemented
|
|
785
804
|
| **Pure Pursuit** ||Not implemented
|
|
786
805
|
| **PID** ||Not implemented
|
|
787
806
|
| **APF** ||Not implemented
|
|
788
807
|
| **DWA** ||Not implemented
|
|
789
|
-
| **RPP**
|
|
808
|
+
| **RPP** ||Not implemented
|
|
790
809
|
| **LQR** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
791
810
|
| **MPC** |Implemented in [V1.1.1](https://github.com/ai-winter/python_motion_planning/tree/v1.1.1), not migrated|Not implemented
|
|
792
811
|
| **MPPI** |Not implemented|Not implemented
|
|
@@ -795,19 +814,42 @@ In the following demos, the blue robot 1 is the `CircularRobot`, and the orange
|
|
|
795
814
|
| **DQN** |Not implemented|Not implemented
|
|
796
815
|
| **DDPG** |Implemented in [V1.0](https://github.com/ai-winter/python_motion_planning/tree/v1.0), not migrated|Not implemented
|
|
797
816
|
|
|
798
|
-
##
|
|
817
|
+
## Trajectory Optimizer
|
|
818
|
+
### Curve Generator
|
|
819
|
+
#### Point-based
|
|
799
820
|
|
|
800
|
-
|
|
821
|
+
|Generator|2D|3D|
|
|
822
|
+
| ------- | -------------------------------------------------------- | --------------------------------------------------------
|
|
823
|
+
| **Cubic Spline** ||Not implemented
|
|
824
|
+
| **BSpline** ||Not implemented
|
|
801
825
|
|
|
802
|
-
|
|
826
|
+
#### Pose-based
|
|
827
|
+
|Generator|2D|3D|
|
|
803
828
|
| ------- | -------------------------------------------------------- | --------------------------------------------------------
|
|
804
|
-
| **Polynomia** | |Not implemented
|
|
830
|
+
| **Bezier** ||Not implemented
|
|
831
|
+
| **Dubins** ||Not implemented
|
|
832
|
+
| **Reeds-Shepp** ||Not implemented
|
|
833
|
+
|
|
834
|
+
# Future Works
|
|
835
|
+
|
|
836
|
+
* N-D controllers (path-trackers).
|
|
837
|
+
|
|
838
|
+
* Path planning for robotic arms.
|
|
839
|
+
|
|
840
|
+
* Path planning on topological map.
|
|
841
|
+
|
|
842
|
+
* Sample search with Dubins or Reeds-Shepp curves.
|
|
843
|
+
|
|
844
|
+
* Application on ROS2.
|
|
845
|
+
|
|
846
|
+
* Application in mainstream robot simulation environments (e.g. Gazebo, Carla, Airsim, PyBullet, MuJoCo, Issac Sim).
|
|
847
|
+
|
|
848
|
+
* More mainstream motion planning algorithms.
|
|
849
|
+
|
|
850
|
+
* Performance optimization.
|
|
851
|
+
|
|
852
|
+
Contributors are welcome! For trivial modification, please directly contribute to `dev` branch. For big modification, please [contact](#contact) us before you contribute.
|
|
811
853
|
|
|
812
854
|
# Contact
|
|
813
855
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
python_motion_planning/__init__.py,sha256=qsRVlO3n-WSdeyH6NvduCQJ_G0Yqrml7F_juvs2UnJ4,108
|
|
2
|
+
python_motion_planning/common/__init__.py,sha256=9CeruPgGOBOtro9EafPEhK5VKTav2OWeNbMLJCBwuNg,67
|
|
3
|
+
python_motion_planning/common/env/__init__.py,sha256=Q8qIUcn5fvtLrmrc3SXStQoEwwrNMF-IofKotFermBk,129
|
|
4
|
+
python_motion_planning/common/env/node.py,sha256=6I10JpU4tjK4aZEMWN7Dttz41QKskNFoe7gBR4aSyII,2727
|
|
5
|
+
python_motion_planning/common/env/types.py,sha256=h5HtPrffu5qH_F1G4V1g8eXBPTPuDW-nFFfEFECVGYo,380
|
|
6
|
+
python_motion_planning/common/env/map/__init__.py,sha256=5bVsJd2mrghKMj7erXfgc8V4NahXHe6zXngG9fMCjo0,44
|
|
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=-QDhKpKrjE4Hi-NZPWIgPiiZagJCZH_dw8QgpHgLor4,28441
|
|
9
|
+
python_motion_planning/common/env/robot/__init__.py,sha256=njq1_k2uWikGH2AjtxoFDdmxqsM1YY5B9nVtIheyx6Y,122
|
|
10
|
+
python_motion_planning/common/env/robot/base_robot.py,sha256=KEajU9iFCnrzDOFp3Vm3SMWJWQgGJAYLT4VB6IMX2Is,7913
|
|
11
|
+
python_motion_planning/common/env/robot/circular_robot.py,sha256=6SS3XP91WfQlccxbtyVLjmPQjgesP9cFaxXg6txkxVI,1512
|
|
12
|
+
python_motion_planning/common/env/robot/diff_drive_robot.py,sha256=bJgaa7sheCb62ee891vEV3KigeX4nUOtec0iw2F7Syw,4389
|
|
13
|
+
python_motion_planning/common/env/world/__init__.py,sha256=nC9YDBuO-8FapouUCe_relatAferP_gcgPkVQ3QCVNA,39
|
|
14
|
+
python_motion_planning/common/env/world/base_world.py,sha256=FSf9PQAFY6CFgCSGK8TNdGDR8_GrIEtBW8CA83jWtEo,4131
|
|
15
|
+
python_motion_planning/common/env/world/toy_simulator.py,sha256=J2JrZhQD-lCd4TB2X6O_wyX_NR_rIz3UjSzPrjyINEQ,9730
|
|
16
|
+
python_motion_planning/common/utils/__init__.py,sha256=wYzKTiyKgYfl5cTO0pUHF1zkr8Q9VhhEwKcRy1xSSdM,114
|
|
17
|
+
python_motion_planning/common/utils/child_tree.py,sha256=f6ypaZ-d7mJpWOaVH99KriJuzjDc6q353USsO7D5F9g,625
|
|
18
|
+
python_motion_planning/common/utils/frame_transformer.py,sha256=D9xaOUcxCPLvTl9oJHRSuhue84i88nMiuI-3ns0i7Ao,7609
|
|
19
|
+
python_motion_planning/common/utils/geometry.py,sha256=FFYM_eVAgJ3wA7H8MRXNvwXliGd6dKo4WU8fzbwdCXE,2693
|
|
20
|
+
python_motion_planning/common/visualizer/__init__.py,sha256=HWWbLehtqEl0q_hEO28tEMDH-v8lXqduN-EJ7mo9LEI,90
|
|
21
|
+
python_motion_planning/common/visualizer/base_visualizer.py,sha256=sjkH8lbyW8q9BVIEaQBTF10M27d73cpQqdTAPbEBFD0,5518
|
|
22
|
+
python_motion_planning/common/visualizer/visualizer_2d.py,sha256=mqaKFZEtNHOCm82I1nCbCOhDP444JSySq1BzQCnPyEM,15656
|
|
23
|
+
python_motion_planning/common/visualizer/visualizer_3d.py,sha256=4LklgQv9Wu7UT8hmJMLiGau_8GzrGcJpQ4Xj40m1rTA,7645
|
|
24
|
+
python_motion_planning/controller/__init__.py,sha256=UGFx5oND_pyovs1LIZ2HYU8Toxo0QnkTSnqKITfX28M,121
|
|
25
|
+
python_motion_planning/controller/base_controller.py,sha256=bSeCXHM10KosvZmGhjHyUOoC-BvxdDWW_Q2IeyGJ-yQ,6890
|
|
26
|
+
python_motion_planning/controller/random_controller.py,sha256=al9Az3K4K8HlfQ-BQNcoS-1T6O2v1-juu8Fw5lL3dEE,693
|
|
27
|
+
python_motion_planning/controller/path_tracker/__init__.py,sha256=1giXD5W8aXdTc1H_DO9P0MK8JjC6Jb_tsnrT3Gz4JDM,164
|
|
28
|
+
python_motion_planning/controller/path_tracker/apf.py,sha256=wV_OiPua5djMwP_i8eZP0FX8e3Y_kov-HsMOmbRGtFE,9531
|
|
29
|
+
python_motion_planning/controller/path_tracker/dwa.py,sha256=EyjXdU_lw_hIN6lucfaokxx8C1OxPCLk13zmcy7KLR8,9495
|
|
30
|
+
python_motion_planning/controller/path_tracker/path_tracker.py,sha256=5p_MhqRWpMGEsdek0IqcohmXCMTlStUrMwSoJKX14zw,9359
|
|
31
|
+
python_motion_planning/controller/path_tracker/pid.py,sha256=pqZggmTWaNd7XrlqfaK4wtBk9syg8PnIC7vOEnfN9S8,2403
|
|
32
|
+
python_motion_planning/controller/path_tracker/pure_pursuit.py,sha256=gsfiMXZx3RwHIwmI2CSu4fTZNFKbZP31cXMgKUdDjs8,2405
|
|
33
|
+
python_motion_planning/controller/path_tracker/rpp.py,sha256=e7qRIaUfeiVfVoiY5k797Yk9RK-Q7gnegmaOB7_BVP4,4181
|
|
34
|
+
python_motion_planning/path_planner/__init__.py,sha256=Y0Im0cJ3iuUOYJyAOYvA_IavaNTNowb7SE6atrdJqX0,121
|
|
35
|
+
python_motion_planning/path_planner/base_path_planner.py,sha256=YZcLqAIkLJtp5MWoT5zPmzxv05xUlnDpfuzN-CgPQuc,3640
|
|
36
|
+
python_motion_planning/path_planner/graph_search/__init__.py,sha256=ugZpHV12dY-yb8d1jx4NepdRzQKn2qNKS6yWEBlvWy0,146
|
|
37
|
+
python_motion_planning/path_planner/graph_search/a_star.py,sha256=s_PLSsF53xcvVM5DOnFDCW5Enp4TrkL1keuPuKWIEEA,2989
|
|
38
|
+
python_motion_planning/path_planner/graph_search/dijkstra.py,sha256=Z3f2KuR2dQ2VAc1jcScD9Qo05qFVUULHhSz58QlHQEk,3169
|
|
39
|
+
python_motion_planning/path_planner/graph_search/gbfs.py,sha256=S9MSwjNavvSiau5sQJRum-Nq0GYInFa6SmfzJfWdxNw,3261
|
|
40
|
+
python_motion_planning/path_planner/graph_search/jps.py,sha256=AOfGLBmSS1HMX_XjvpQKGLH3-e80MwzLGKG0_afXWrE,7657
|
|
41
|
+
python_motion_planning/path_planner/graph_search/lazy_theta_star.py,sha256=Gyu8F16lEqaqfZteRwYeu1UkhWQRnWL0wSJbM7H1oWw,3965
|
|
42
|
+
python_motion_planning/path_planner/graph_search/theta_star.py,sha256=JxxWukRTI4aZWF9pppzpsjqwRh6A6gvfB5YLZIk45w0,3846
|
|
43
|
+
python_motion_planning/path_planner/hybrid_search/__init__.py,sha256=RCvNhSq6nskZPCc7jo9Y5MOzrD4f7TL9RfVUCHgpeq4,30
|
|
44
|
+
python_motion_planning/path_planner/hybrid_search/voronoi_planner.py,sha256=sDTE-IFMf2035mUIRulEIOF0NiZSrwhW_bWrCiPetu4,7897
|
|
45
|
+
python_motion_planning/path_planner/sample_search/__init__.py,sha256=RYz6o_xmdsoErMGdBKvXEK4w-48P_ogi1bJsdJmUupk,71
|
|
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,404 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
multiagent_nav.py
|
|
3
|
-
|
|
4
|
-
依赖: gymnasium, numpy, matplotlib
|
|
5
|
-
|
|
6
|
-
保存并运行后,可通过 demo_2d() / demo_3d() 运行演示。
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from typing import List, Dict, Tuple, Optional
|
|
10
|
-
import numpy as np
|
|
11
|
-
import gymnasium as gym
|
|
12
|
-
from gymnasium import spaces
|
|
13
|
-
import math
|
|
14
|
-
import matplotlib.pyplot as plt
|
|
15
|
-
from matplotlib import animation
|
|
16
|
-
from mpl_toolkits.mplot3d import Axes3D # noqa: F401
|
|
17
|
-
|
|
18
|
-
# ---------------------------
|
|
19
|
-
# Base classes: Agent / Controller / Environment
|
|
20
|
-
# ---------------------------
|
|
21
|
-
|
|
22
|
-
class BaseAgent:
|
|
23
|
-
"""
|
|
24
|
-
Agent 基类:只包含物理参数和状态容器,负责定义观测格式。
|
|
25
|
-
- dim: 空间维度(N)
|
|
26
|
-
- mass: 质量
|
|
27
|
-
- radius: 形状半径(用于碰撞)
|
|
28
|
-
- pos, vel: 当前状态(numpy arrays)
|
|
29
|
-
- acc: 当前瞬时加速度(set by controller before env.step 使用)
|
|
30
|
-
"""
|
|
31
|
-
def __init__(self, dim: int = 2, mass: float = 1.0, radius: float = 0.1,
|
|
32
|
-
pos: Optional[np.ndarray] = None, vel: Optional[np.ndarray] = None,
|
|
33
|
-
action_min: Optional[np.ndarray] = None, action_max: Optional[np.ndarray] = None):
|
|
34
|
-
self.dim = dim
|
|
35
|
-
self.mass = float(mass)
|
|
36
|
-
self.radius = float(radius)
|
|
37
|
-
self.pos = np.zeros(dim) if pos is None else np.array(pos, dtype=float)
|
|
38
|
-
self.vel = np.zeros(dim) if vel is None else np.array(vel, dtype=float)
|
|
39
|
-
# acceleration is set externally by controller each step
|
|
40
|
-
self.acc = np.zeros(dim)
|
|
41
|
-
# action bounds per-dim (controller output bounds)
|
|
42
|
-
if action_min is None:
|
|
43
|
-
action_min = -np.ones(dim) * 1.0
|
|
44
|
-
if action_max is None:
|
|
45
|
-
action_max = np.ones(dim) * 1.0
|
|
46
|
-
self.action_min = np.array(action_min, dtype=float)
|
|
47
|
-
self.action_max = np.array(action_max, dtype=float)
|
|
48
|
-
|
|
49
|
-
def observation_size(self, env) -> int:
|
|
50
|
-
"""
|
|
51
|
-
默认观测:自身 pos, vel (2*dim) + 所有其他 agent 的相对位置 ( (n-1)*dim )
|
|
52
|
-
你可以重载该函数改变观测结构。
|
|
53
|
-
"""
|
|
54
|
-
n_agents = len(env.agents)
|
|
55
|
-
return 2 * self.dim + (n_agents - 1) * self.dim
|
|
56
|
-
|
|
57
|
-
def get_observation(self, env) -> np.ndarray:
|
|
58
|
-
"""
|
|
59
|
-
返回观测向量(1D numpy array)。
|
|
60
|
-
默认格式: [pos, vel, rel_pos_agent1, rel_pos_agent2, ...]
|
|
61
|
-
相对位置按照 env.agents 列表顺序(跳过 self)。
|
|
62
|
-
"""
|
|
63
|
-
obs = []
|
|
64
|
-
obs.extend(self.pos.tolist())
|
|
65
|
-
obs.extend(self.vel.tolist())
|
|
66
|
-
for a in env.agents:
|
|
67
|
-
if a is self:
|
|
68
|
-
continue
|
|
69
|
-
rel = (a.pos - self.pos)
|
|
70
|
-
obs.extend(rel.tolist())
|
|
71
|
-
return np.array(obs, dtype=float)
|
|
72
|
-
|
|
73
|
-
def clip_action(self, a: np.ndarray) -> np.ndarray:
|
|
74
|
-
return np.minimum(np.maximum(a, self.action_min), self.action_max)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class SimpleAgent(BaseAgent):
|
|
78
|
-
"""一个简单的圆/球体 agent(继承 BaseAgent)。"""
|
|
79
|
-
pass
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class BaseController:
|
|
83
|
-
"""
|
|
84
|
-
Controller 基类(与环境解耦)
|
|
85
|
-
- 控制器只知道:observation_space, action_space(由 agent 定义)
|
|
86
|
-
- get_action(obs) -> acceleration vector (dim,)
|
|
87
|
-
"""
|
|
88
|
-
def __init__(self, observation_space: spaces.Space, action_space: spaces.Box):
|
|
89
|
-
self.observation_space = observation_space
|
|
90
|
-
self.action_space = action_space
|
|
91
|
-
|
|
92
|
-
def reset(self):
|
|
93
|
-
"""可选:用于在每个 episode 开始时清理内部状态。"""
|
|
94
|
-
pass
|
|
95
|
-
|
|
96
|
-
def get_action(self, obs: np.ndarray) -> np.ndarray:
|
|
97
|
-
"""子类必须实现:返回与 action_space.shape 匹配的 ndarray(加速度)"""
|
|
98
|
-
raise NotImplementedError
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class RandomController(BaseController):
|
|
102
|
-
"""默认随机控制器:在 action_space 内均匀采样。"""
|
|
103
|
-
def get_action(self, obs: np.ndarray) -> np.ndarray:
|
|
104
|
-
return self.action_space.sample()
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# ---------------------------
|
|
108
|
-
# Environment
|
|
109
|
-
# ---------------------------
|
|
110
|
-
|
|
111
|
-
class MultiAgentNavEnv(gym.Env):
|
|
112
|
-
"""
|
|
113
|
-
多智能体导航环境(可 N 维)
|
|
114
|
-
- agents: list of BaseAgent 的实例
|
|
115
|
-
- bounds: environment boundary as (min_vec, max_vec) each of length dim
|
|
116
|
-
- dt: 时间步长
|
|
117
|
-
- friction: 线性阻尼系数(v * (-friction) force),模型里转成加速度影响
|
|
118
|
-
- restitution: 边界/碰撞弹性系数 [0,1]
|
|
119
|
-
- max_episode_steps: 可选终止步数
|
|
120
|
-
"""
|
|
121
|
-
metadata = {"render.modes": ["human"]}
|
|
122
|
-
|
|
123
|
-
def __init__(self, dim: int = 2,
|
|
124
|
-
bounds: Tuple[np.ndarray, np.ndarray] = None,
|
|
125
|
-
dt: float = 0.05,
|
|
126
|
-
friction: float = 0.1,
|
|
127
|
-
restitution: float = 0.9,
|
|
128
|
-
max_episode_steps: int = 1000):
|
|
129
|
-
super().__init__()
|
|
130
|
-
self.dim = dim
|
|
131
|
-
if bounds is None:
|
|
132
|
-
lo = -np.ones(dim) * 5.0
|
|
133
|
-
hi = np.ones(dim) * 5.0
|
|
134
|
-
bounds = (lo, hi)
|
|
135
|
-
self.bounds = (np.array(bounds[0], dtype=float), np.array(bounds[1], dtype=float))
|
|
136
|
-
self.dt = float(dt)
|
|
137
|
-
self.friction = float(friction)
|
|
138
|
-
self.restitution = float(restitution)
|
|
139
|
-
self.max_episode_steps = int(max_episode_steps)
|
|
140
|
-
|
|
141
|
-
self.agents: List[BaseAgent] = []
|
|
142
|
-
self.step_count = 0
|
|
143
|
-
# observation_space and action_space are per-agent; environment doesn't expose global spaces
|
|
144
|
-
# 但为了兼容 gym,提供 a dummy space
|
|
145
|
-
self.observation_space = spaces.Box(-np.inf, np.inf, shape=(1,), dtype=float)
|
|
146
|
-
self.action_space = spaces.Box(-np.inf, np.inf, shape=(1,), dtype=float)
|
|
147
|
-
|
|
148
|
-
def add_agent(self, agent: BaseAgent):
|
|
149
|
-
if agent.dim != self.dim:
|
|
150
|
-
raise ValueError("Agent dimension must match environment dimension")
|
|
151
|
-
self.agents.append(agent)
|
|
152
|
-
|
|
153
|
-
def reset(self, seed: Optional[int] = None):
|
|
154
|
-
self.step_count = 0
|
|
155
|
-
# optionally randomize initial states or rely on agents' initial pos/vel
|
|
156
|
-
# 返回 dict of observations keyed by agent index
|
|
157
|
-
obs = {}
|
|
158
|
-
for i, a in enumerate(self.agents):
|
|
159
|
-
obs[i] = a.get_observation(self)
|
|
160
|
-
return obs, {}
|
|
161
|
-
|
|
162
|
-
def step(self, actions: Dict[int, np.ndarray]):
|
|
163
|
-
"""
|
|
164
|
-
actions: dict mapping agent_index -> acceleration ndarray (dim,)
|
|
165
|
-
1) clip to agent action bounds
|
|
166
|
-
2) apply environment forces (friction) and integrate via semi-implicit Euler
|
|
167
|
-
3) handle collisions (agent-agent, agent-boundary)
|
|
168
|
-
返回:obs_dict, reward_dict, done_dict, info
|
|
169
|
-
"""
|
|
170
|
-
self.step_count += 1
|
|
171
|
-
# 1. assign actions (accelerations) to agents
|
|
172
|
-
for i, a in enumerate(self.agents):
|
|
173
|
-
act = actions.get(i, np.zeros(self.dim))
|
|
174
|
-
a.acc = a.clip_action(np.array(act, dtype=float))
|
|
175
|
-
|
|
176
|
-
# 2. apply environment forces -> compute net acceleration: a_net = a.acc + a_env (friction)
|
|
177
|
-
for a in self.agents:
|
|
178
|
-
# friction as linear damping: a_fric = -friction * v / mass
|
|
179
|
-
a_env_acc = - self.friction * a.vel / (a.mass + 1e-12)
|
|
180
|
-
a_net = a.acc + a_env_acc
|
|
181
|
-
# semi-implicit Euler: v += a_net*dt, pos += v*dt
|
|
182
|
-
a.vel = a.vel + a_net * self.dt
|
|
183
|
-
a.pos = a.pos + a.vel * self.dt
|
|
184
|
-
|
|
185
|
-
# 3. collisions: pairwise agent-agent elastic collisions (simple impulse) and boundary collisions
|
|
186
|
-
self._resolve_agent_collisions()
|
|
187
|
-
self._resolve_boundary_collisions()
|
|
188
|
-
|
|
189
|
-
obs = {i: a.get_observation(self) for i, a in enumerate(self.agents)}
|
|
190
|
-
# no rewards by default; you can extend
|
|
191
|
-
rewards = {i: 0.0 for i in range(len(self.agents))}
|
|
192
|
-
dones = {i: False for i in range(len(self.agents))}
|
|
193
|
-
terminated = False
|
|
194
|
-
truncated = self.step_count >= self.max_episode_steps
|
|
195
|
-
info = {}
|
|
196
|
-
return obs, rewards, dones, {"terminated": terminated, "truncated": truncated, **info}
|
|
197
|
-
|
|
198
|
-
def _resolve_agent_collisions(self):
|
|
199
|
-
n = len(self.agents)
|
|
200
|
-
for i in range(n):
|
|
201
|
-
for j in range(i + 1, n):
|
|
202
|
-
a = self.agents[i]
|
|
203
|
-
b = self.agents[j]
|
|
204
|
-
delta = b.pos - a.pos
|
|
205
|
-
dist = np.linalg.norm(delta)
|
|
206
|
-
min_dist = a.radius + b.radius
|
|
207
|
-
if dist < 1e-8:
|
|
208
|
-
# numeric edge-case: jitter them slightly
|
|
209
|
-
delta = np.random.randn(self.dim) * 1e-6
|
|
210
|
-
dist = np.linalg.norm(delta)
|
|
211
|
-
if dist < min_dist:
|
|
212
|
-
# push them apart and compute elastic collision impulse
|
|
213
|
-
# normal vector
|
|
214
|
-
nvec = delta / dist
|
|
215
|
-
# relative velocity along normal
|
|
216
|
-
rel_vel = np.dot(b.vel - a.vel, nvec)
|
|
217
|
-
# compute impulse scalar (elastic) with restitution
|
|
218
|
-
e = self.restitution
|
|
219
|
-
j_impulse = -(1 + e) * rel_vel / (1 / a.mass + 1 / b.mass)
|
|
220
|
-
if j_impulse < 0:
|
|
221
|
-
# apply impulse
|
|
222
|
-
a.vel = a.vel - (j_impulse / a.mass) * nvec
|
|
223
|
-
b.vel = b.vel + (j_impulse / b.mass) * nvec
|
|
224
|
-
# positional correction (simple)
|
|
225
|
-
overlap = min_dist - dist
|
|
226
|
-
corr = nvec * (overlap / 2.0 + 1e-6)
|
|
227
|
-
a.pos = a.pos - corr
|
|
228
|
-
b.pos = b.pos + corr
|
|
229
|
-
|
|
230
|
-
def _resolve_boundary_collisions(self):
|
|
231
|
-
lo, hi = self.bounds
|
|
232
|
-
for a in self.agents:
|
|
233
|
-
for d in range(self.dim):
|
|
234
|
-
if a.pos[d] - a.radius < lo[d]:
|
|
235
|
-
a.pos[d] = lo[d] + a.radius
|
|
236
|
-
if a.vel[d] < 0:
|
|
237
|
-
a.vel[d] = -a.vel[d] * self.restitution
|
|
238
|
-
elif a.pos[d] + a.radius > hi[d]:
|
|
239
|
-
a.pos[d] = hi[d] - a.radius
|
|
240
|
-
if a.vel[d] > 0:
|
|
241
|
-
a.vel[d] = -a.vel[d] * self.restitution
|
|
242
|
-
|
|
243
|
-
def render(self, mode="human", ax=None):
|
|
244
|
-
# delegated to demo functions; keep signature for Gym compatibility
|
|
245
|
-
raise NotImplementedError("render(): use provided demo_2d/demo_3d functions for visualization.")
|
|
246
|
-
|
|
247
|
-
def close(self):
|
|
248
|
-
pass
|
|
249
|
-
|
|
250
|
-
# helper to build spaces per-agent
|
|
251
|
-
def build_agent_spaces(self, agent: BaseAgent) -> Tuple[spaces.Box, spaces.Box]:
|
|
252
|
-
"""
|
|
253
|
-
返回 (observation_space, action_space) for given agent
|
|
254
|
-
observation_space: shape (observation_size,)
|
|
255
|
-
action_space: shape (dim,) bounded by agent.action_min / action_max
|
|
256
|
-
"""
|
|
257
|
-
obs_dim = agent.observation_size(self)
|
|
258
|
-
obs_low = -np.inf * np.ones(obs_dim)
|
|
259
|
-
obs_high = np.inf * np.ones(obs_dim)
|
|
260
|
-
obs_space = spaces.Box(obs_low, obs_high, dtype=float)
|
|
261
|
-
act_low = agent.action_min
|
|
262
|
-
act_high = agent.action_max
|
|
263
|
-
act_space = spaces.Box(act_low, act_high, dtype=float)
|
|
264
|
-
return obs_space, act_space
|
|
265
|
-
|
|
266
|
-
# ---------------------------
|
|
267
|
-
# Demos: 2D & 3D visualization
|
|
268
|
-
# ---------------------------
|
|
269
|
-
|
|
270
|
-
def demo_2d():
|
|
271
|
-
"""
|
|
272
|
-
2D 演示:生成 N 个圆形 agent,RandomController 控制,使用 matplotlib 动画绘制。
|
|
273
|
-
"""
|
|
274
|
-
dim = 2
|
|
275
|
-
env = MultiAgentNavEnv(dim=dim, bounds=(np.array([-5, -5]), np.array([5, 5])),
|
|
276
|
-
dt=0.03, friction=0.2, restitution=0.8, max_episode_steps=1000)
|
|
277
|
-
|
|
278
|
-
# add agents with different masses/radii and action limits per-dim
|
|
279
|
-
agents = [
|
|
280
|
-
SimpleAgent(dim=dim, mass=1.0, radius=0.25, pos=np.array([-3.0, -3.0]), vel=np.zeros(dim),
|
|
281
|
-
action_min=np.array([-2.0, -2.0]), action_max=np.array([2.0, 2.0])),
|
|
282
|
-
SimpleAgent(dim=dim, mass=2.0, radius=0.35, pos=np.array([3.0, -3.0]), vel=np.zeros(dim),
|
|
283
|
-
action_min=np.array([-1.5, -1.5]), action_max=np.array([1.5, 1.5])),
|
|
284
|
-
SimpleAgent(dim=dim, mass=1.2, radius=0.2, pos=np.array([0.0, 3.0]), vel=np.zeros(dim),
|
|
285
|
-
action_min=np.array([-3.0, -3.0]), action_max=np.array([3.0, 3.0])),
|
|
286
|
-
]
|
|
287
|
-
for a in agents:
|
|
288
|
-
env.add_agent(a)
|
|
289
|
-
|
|
290
|
-
# build controllers per-agent (Random by default)
|
|
291
|
-
controllers = []
|
|
292
|
-
for i, a in enumerate(env.agents):
|
|
293
|
-
obs_space, act_space = env.build_agent_spaces(a)
|
|
294
|
-
controllers.append(RandomController(obs_space, act_space))
|
|
295
|
-
|
|
296
|
-
obs, _ = env.reset()
|
|
297
|
-
|
|
298
|
-
# matplotlib setup
|
|
299
|
-
fig, ax = plt.subplots(figsize=(6, 6))
|
|
300
|
-
lo, hi = env.bounds
|
|
301
|
-
ax.set_xlim(lo[0], hi[0])
|
|
302
|
-
ax.set_ylim(lo[1], hi[1])
|
|
303
|
-
ax.set_aspect('equal')
|
|
304
|
-
patches = []
|
|
305
|
-
texts = []
|
|
306
|
-
colors = ['C0', 'C1', 'C2', 'C3', 'C4']
|
|
307
|
-
for i, a in enumerate(env.agents):
|
|
308
|
-
p = plt.Circle(tuple(a.pos), a.radius, color=colors[i % len(colors)], alpha=0.8)
|
|
309
|
-
patches.append(p)
|
|
310
|
-
ax.add_patch(p)
|
|
311
|
-
t = ax.text(*a.pos, f"{i}", color='white', ha='center', va='center')
|
|
312
|
-
texts.append(t)
|
|
313
|
-
|
|
314
|
-
# animation update
|
|
315
|
-
def update(frame):
|
|
316
|
-
actions = {}
|
|
317
|
-
for i, a in enumerate(env.agents):
|
|
318
|
-
ob = a.get_observation(env)
|
|
319
|
-
act = controllers[i].get_action(ob)
|
|
320
|
-
actions[i] = act
|
|
321
|
-
obs, rewards, dones, info = env.step(actions)
|
|
322
|
-
for i, a in enumerate(env.agents):
|
|
323
|
-
patches[i].center = tuple(a.pos)
|
|
324
|
-
texts[i].set_position(tuple(a.pos))
|
|
325
|
-
return patches + texts
|
|
326
|
-
|
|
327
|
-
ani = animation.FuncAnimation(fig, update, frames=400, interval=30, blit=False)
|
|
328
|
-
plt.title("Multi-Agent Navigation 2D Demo (Random Controllers)")
|
|
329
|
-
plt.show()
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
def demo_3d():
|
|
333
|
-
"""
|
|
334
|
-
3D 演示:类似 2D,但用 mpl_toolkits.mplot3d 展示球体(用 scatter 表示)。
|
|
335
|
-
注意:matplotlib 3D 动画较慢,但用于快速验证足够。
|
|
336
|
-
"""
|
|
337
|
-
dim = 3
|
|
338
|
-
env = MultiAgentNavEnv(dim=dim, bounds=(np.array([-5, -5, -2]), np.array([5, 5, 2])),
|
|
339
|
-
dt=0.05, friction=0.15, restitution=0.85, max_episode_steps=1000)
|
|
340
|
-
|
|
341
|
-
agents = [
|
|
342
|
-
SimpleAgent(dim=dim, mass=1.0, radius=0.25, pos=np.array([-3.0, -3.0, 0.0]),
|
|
343
|
-
action_min=np.array([-2.0, -2.0, -1.0]), action_max=np.array([2.0, 2.0, 1.0])),
|
|
344
|
-
SimpleAgent(dim=dim, mass=1.5, radius=0.3, pos=np.array([3.0, -3.0, 0.5]),
|
|
345
|
-
action_min=np.array([-1.5, -1.5, -1.0]), action_max=np.array([1.5, 1.5, 1.0])),
|
|
346
|
-
SimpleAgent(dim=dim, mass=0.8, radius=0.2, pos=np.array([0.0, 3.0, -0.5]),
|
|
347
|
-
action_min=np.array([-3.0, -3.0, -1.0]), action_max=np.array([3.0, 3.0, 1.0])),
|
|
348
|
-
]
|
|
349
|
-
for a in agents:
|
|
350
|
-
env.add_agent(a)
|
|
351
|
-
|
|
352
|
-
controllers = []
|
|
353
|
-
for i, a in enumerate(env.agents):
|
|
354
|
-
obs_space, act_space = env.build_agent_spaces(a)
|
|
355
|
-
controllers.append(RandomController(obs_space, act_space))
|
|
356
|
-
|
|
357
|
-
obs, _ = env.reset()
|
|
358
|
-
|
|
359
|
-
# matplotlib 3d setup
|
|
360
|
-
fig = plt.figure(figsize=(8, 6))
|
|
361
|
-
ax = fig.add_subplot(111, projection='3d')
|
|
362
|
-
lo, hi = env.bounds
|
|
363
|
-
ax.set_xlim(lo[0], hi[0])
|
|
364
|
-
ax.set_ylim(lo[1], hi[1])
|
|
365
|
-
ax.set_zlim(lo[2], hi[2])
|
|
366
|
-
scat = ax.scatter([a.pos[0] for a in env.agents],
|
|
367
|
-
[a.pos[1] for a in env.agents],
|
|
368
|
-
[a.pos[2] for a in env.agents],
|
|
369
|
-
s=[(a.radius * 1000) for a in env.agents])
|
|
370
|
-
|
|
371
|
-
# annotation labels
|
|
372
|
-
annotations = [ax.text(a.pos[0], a.pos[1], a.pos[2], str(i)) for i, a in enumerate(env.agents)]
|
|
373
|
-
|
|
374
|
-
def update(frame):
|
|
375
|
-
actions = {}
|
|
376
|
-
for i, a in enumerate(env.agents):
|
|
377
|
-
ob = a.get_observation(env)
|
|
378
|
-
act = controllers[i].get_action(ob)
|
|
379
|
-
actions[i] = act
|
|
380
|
-
obs, rewards, dones, info = env.step(actions)
|
|
381
|
-
xs = [a.pos[0] for a in env.agents]
|
|
382
|
-
ys = [a.pos[1] for a in env.agents]
|
|
383
|
-
zs = [a.pos[2] for a in env.agents]
|
|
384
|
-
scat._offsets3d = (xs, ys, zs)
|
|
385
|
-
for i, ann in enumerate(annotations):
|
|
386
|
-
ann.set_position((xs[i], ys[i]))
|
|
387
|
-
# can't directly set z of text easily; remove & redraw would be heavy
|
|
388
|
-
return scat, *annotations
|
|
389
|
-
|
|
390
|
-
ani = animation.FuncAnimation(fig, update, frames=400, interval=50, blit=False)
|
|
391
|
-
plt.title("Multi-Agent Navigation 3D Demo (Random Controllers)")
|
|
392
|
-
plt.show()
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
# ---------------------------
|
|
396
|
-
# Example usage
|
|
397
|
-
# ---------------------------
|
|
398
|
-
|
|
399
|
-
if __name__ == "__main__":
|
|
400
|
-
# 运行 2D 或 3D demo
|
|
401
|
-
# print("Running 2D demo...")
|
|
402
|
-
demo_2d()
|
|
403
|
-
# 若要运行 3D,注释上两行,解除下一行注释:
|
|
404
|
-
# demo_3d()
|