roboticstoolbox-python 1.3.0__cp312-cp312-win_amd64.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.
- roboticstoolbox/__init__.py +104 -0
- roboticstoolbox/backends/Connector.py +107 -0
- roboticstoolbox/backends/Dynamixel/README.md +9 -0
- roboticstoolbox/backends/Dynamixel/dynamixel.json +581 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_io.py +450 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/LICENSE +201 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/README.md +28 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/ReleaseNote.md +181 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/__init__.py +27 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/group_bulk_read.py +163 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/group_bulk_write.py +109 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/group_sync_read.py +166 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/group_sync_write.py +99 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/packet_handler.py +33 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/port_handler.py +155 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/protocol1_packet_handler.py +548 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/protocol2_packet_handler.py +1080 -0
- roboticstoolbox/backends/Dynamixel/dynamixel_sdk/robotis_def.py +75 -0
- roboticstoolbox/backends/Dynamixel/dyndata.py +121 -0
- roboticstoolbox/backends/PyPlot/EllipsePlot.py +253 -0
- roboticstoolbox/backends/PyPlot/PyPlot.py +769 -0
- roboticstoolbox/backends/PyPlot/PyPlot2.py +526 -0
- roboticstoolbox/backends/PyPlot/README.md +67 -0
- roboticstoolbox/backends/PyPlot/RobotPlot.py +247 -0
- roboticstoolbox/backends/PyPlot/RobotPlot2.py +123 -0
- roboticstoolbox/backends/PyPlot/__init__.py +4 -0
- roboticstoolbox/backends/ROS/ROS.py +129 -0
- roboticstoolbox/backends/ROS/__init__.py +3 -0
- roboticstoolbox/backends/__init__.py +39 -0
- roboticstoolbox/backends/swift/__init__.py +26 -0
- roboticstoolbox/bin/__init__.py +0 -0
- roboticstoolbox/bin/rtbtool.py +307 -0
- roboticstoolbox/blocks/Icons/250x250/armplot.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/bicycle.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/camera.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/circlepath.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/coriolis.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/ctraj.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/delta2tr.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/diffsteer.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/fdyn.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/fdynx.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/fkine.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/gravload.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/idyn.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/idynx.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/ikine.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/inertia.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/jacobian.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/jtraj.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/lspb.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/multirotor.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/multirotormixer.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/multirotorplot.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/point2tr.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/tr2delta.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/tr2t.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/unicycle.png +0 -0
- roboticstoolbox/blocks/Icons/250x250/vehicleplot.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/armplot.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/bicycle.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/camera.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/circlepath.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/coriolis.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/delta2tr.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/diffsteer.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/fdyn.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/fdynx.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/fkine.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/gravload.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/idyn.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/idynx.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/ikine.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/inertia.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/jacobian.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/jtraj.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/lspb.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/multirotor.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/multirotormixer.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/multirotorplot.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/point2tr.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/tr2delta.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/tr2t.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/unicycle.png +0 -0
- roboticstoolbox/blocks/Icons/50x50/vehicleplot.png +0 -0
- roboticstoolbox/blocks/Icons/armplot.png +0 -0
- roboticstoolbox/blocks/Icons/bicycle.png +0 -0
- roboticstoolbox/blocks/Icons/camera.png +0 -0
- roboticstoolbox/blocks/Icons/circlepath.png +0 -0
- roboticstoolbox/blocks/Icons/coriolis.png +0 -0
- roboticstoolbox/blocks/Icons/ctraj.png +0 -0
- roboticstoolbox/blocks/Icons/delta2tr.png +0 -0
- roboticstoolbox/blocks/Icons/diffsteer.png +0 -0
- roboticstoolbox/blocks/Icons/fdyn.png +0 -0
- roboticstoolbox/blocks/Icons/fdynx.png +0 -0
- roboticstoolbox/blocks/Icons/fkine.png +0 -0
- roboticstoolbox/blocks/Icons/gravload.png +0 -0
- roboticstoolbox/blocks/Icons/idyn.png +0 -0
- roboticstoolbox/blocks/Icons/idynx.png +0 -0
- roboticstoolbox/blocks/Icons/ikine.png +0 -0
- roboticstoolbox/blocks/Icons/inertia.png +0 -0
- roboticstoolbox/blocks/Icons/jacobian.png +0 -0
- roboticstoolbox/blocks/Icons/jtraj.png +0 -0
- roboticstoolbox/blocks/Icons/lspb.png +0 -0
- roboticstoolbox/blocks/Icons/multirotor.png +0 -0
- roboticstoolbox/blocks/Icons/multirotormixer.png +0 -0
- roboticstoolbox/blocks/Icons/multirotorplot.png +0 -0
- roboticstoolbox/blocks/Icons/point2tr.png +0 -0
- roboticstoolbox/blocks/Icons/tr2delta.png +0 -0
- roboticstoolbox/blocks/Icons/tr2t.png +0 -0
- roboticstoolbox/blocks/Icons/unicycle.png +0 -0
- roboticstoolbox/blocks/Icons/vehicleplot.png +0 -0
- roboticstoolbox/blocks/README.md +43 -0
- roboticstoolbox/blocks/__init__.py +6 -0
- roboticstoolbox/blocks/arm.py +1587 -0
- roboticstoolbox/blocks/mobile.py +500 -0
- roboticstoolbox/blocks/quad_model.py +132 -0
- roboticstoolbox/blocks/spatial.py +245 -0
- roboticstoolbox/blocks/uav.py +949 -0
- roboticstoolbox/core/Eigen/Cholesky +45 -0
- roboticstoolbox/core/Eigen/CholmodSupport +48 -0
- roboticstoolbox/core/Eigen/Core +384 -0
- roboticstoolbox/core/Eigen/Dense +7 -0
- roboticstoolbox/core/Eigen/Eigen +2 -0
- roboticstoolbox/core/Eigen/Eigenvalues +60 -0
- roboticstoolbox/core/Eigen/Geometry +59 -0
- roboticstoolbox/core/Eigen/Householder +29 -0
- roboticstoolbox/core/Eigen/IterativeLinearSolvers +48 -0
- roboticstoolbox/core/Eigen/Jacobi +32 -0
- roboticstoolbox/core/Eigen/KLUSupport +41 -0
- roboticstoolbox/core/Eigen/LU +47 -0
- roboticstoolbox/core/Eigen/MetisSupport +35 -0
- roboticstoolbox/core/Eigen/OrderingMethods +70 -0
- roboticstoolbox/core/Eigen/PaStiXSupport +49 -0
- roboticstoolbox/core/Eigen/PardisoSupport +35 -0
- roboticstoolbox/core/Eigen/QR +50 -0
- roboticstoolbox/core/Eigen/QtAlignedMalloc +39 -0
- roboticstoolbox/core/Eigen/SPQRSupport +34 -0
- roboticstoolbox/core/Eigen/SVD +50 -0
- roboticstoolbox/core/Eigen/Sparse +34 -0
- roboticstoolbox/core/Eigen/SparseCholesky +37 -0
- roboticstoolbox/core/Eigen/SparseCore +69 -0
- roboticstoolbox/core/Eigen/SparseLU +50 -0
- roboticstoolbox/core/Eigen/SparseQR +36 -0
- roboticstoolbox/core/Eigen/StdDeque +27 -0
- roboticstoolbox/core/Eigen/StdList +26 -0
- roboticstoolbox/core/Eigen/StdVector +27 -0
- roboticstoolbox/core/Eigen/SuperLUSupport +64 -0
- roboticstoolbox/core/Eigen/UmfPackSupport +40 -0
- roboticstoolbox/core/Eigen/src/Cholesky/LDLT.h +688 -0
- roboticstoolbox/core/Eigen/src/Cholesky/LLT.h +558 -0
- roboticstoolbox/core/Eigen/src/Cholesky/LLT_LAPACKE.h +99 -0
- roboticstoolbox/core/Eigen/src/CholmodSupport/CholmodSupport.h +682 -0
- roboticstoolbox/core/Eigen/src/Core/ArithmeticSequence.h +413 -0
- roboticstoolbox/core/Eigen/src/Core/Array.h +417 -0
- roboticstoolbox/core/Eigen/src/Core/ArrayBase.h +226 -0
- roboticstoolbox/core/Eigen/src/Core/ArrayWrapper.h +209 -0
- roboticstoolbox/core/Eigen/src/Core/Assign.h +90 -0
- roboticstoolbox/core/Eigen/src/Core/AssignEvaluator.h +1010 -0
- roboticstoolbox/core/Eigen/src/Core/Assign_MKL.h +178 -0
- roboticstoolbox/core/Eigen/src/Core/BandMatrix.h +353 -0
- roboticstoolbox/core/Eigen/src/Core/Block.h +448 -0
- roboticstoolbox/core/Eigen/src/Core/BooleanRedux.h +162 -0
- roboticstoolbox/core/Eigen/src/Core/CommaInitializer.h +164 -0
- roboticstoolbox/core/Eigen/src/Core/ConditionEstimator.h +175 -0
- roboticstoolbox/core/Eigen/src/Core/CoreEvaluators.h +1741 -0
- roboticstoolbox/core/Eigen/src/Core/CoreIterators.h +132 -0
- roboticstoolbox/core/Eigen/src/Core/CwiseBinaryOp.h +183 -0
- roboticstoolbox/core/Eigen/src/Core/CwiseNullaryOp.h +1001 -0
- roboticstoolbox/core/Eigen/src/Core/CwiseTernaryOp.h +197 -0
- roboticstoolbox/core/Eigen/src/Core/CwiseUnaryOp.h +103 -0
- roboticstoolbox/core/Eigen/src/Core/CwiseUnaryView.h +132 -0
- roboticstoolbox/core/Eigen/src/Core/DenseBase.h +701 -0
- roboticstoolbox/core/Eigen/src/Core/DenseCoeffsBase.h +685 -0
- roboticstoolbox/core/Eigen/src/Core/DenseStorage.h +652 -0
- roboticstoolbox/core/Eigen/src/Core/Diagonal.h +258 -0
- roboticstoolbox/core/Eigen/src/Core/DiagonalMatrix.h +391 -0
- roboticstoolbox/core/Eigen/src/Core/DiagonalProduct.h +28 -0
- roboticstoolbox/core/Eigen/src/Core/Dot.h +318 -0
- roboticstoolbox/core/Eigen/src/Core/EigenBase.h +160 -0
- roboticstoolbox/core/Eigen/src/Core/ForceAlignedAccess.h +150 -0
- roboticstoolbox/core/Eigen/src/Core/Fuzzy.h +155 -0
- roboticstoolbox/core/Eigen/src/Core/GeneralProduct.h +465 -0
- roboticstoolbox/core/Eigen/src/Core/GenericPacketMath.h +1040 -0
- roboticstoolbox/core/Eigen/src/Core/GlobalFunctions.h +194 -0
- roboticstoolbox/core/Eigen/src/Core/IO.h +258 -0
- roboticstoolbox/core/Eigen/src/Core/IndexedView.h +237 -0
- roboticstoolbox/core/Eigen/src/Core/Inverse.h +117 -0
- roboticstoolbox/core/Eigen/src/Core/Map.h +171 -0
- roboticstoolbox/core/Eigen/src/Core/MapBase.h +310 -0
- roboticstoolbox/core/Eigen/src/Core/MathFunctions.h +2057 -0
- roboticstoolbox/core/Eigen/src/Core/MathFunctionsImpl.h +200 -0
- roboticstoolbox/core/Eigen/src/Core/Matrix.h +565 -0
- roboticstoolbox/core/Eigen/src/Core/MatrixBase.h +547 -0
- roboticstoolbox/core/Eigen/src/Core/NestByValue.h +85 -0
- roboticstoolbox/core/Eigen/src/Core/NoAlias.h +109 -0
- roboticstoolbox/core/Eigen/src/Core/NumTraits.h +335 -0
- roboticstoolbox/core/Eigen/src/Core/PartialReduxEvaluator.h +232 -0
- roboticstoolbox/core/Eigen/src/Core/PermutationMatrix.h +605 -0
- roboticstoolbox/core/Eigen/src/Core/PlainObjectBase.h +1128 -0
- roboticstoolbox/core/Eigen/src/Core/Product.h +191 -0
- roboticstoolbox/core/Eigen/src/Core/ProductEvaluators.h +1179 -0
- roboticstoolbox/core/Eigen/src/Core/Random.h +218 -0
- roboticstoolbox/core/Eigen/src/Core/Redux.h +515 -0
- roboticstoolbox/core/Eigen/src/Core/Ref.h +381 -0
- roboticstoolbox/core/Eigen/src/Core/Replicate.h +142 -0
- roboticstoolbox/core/Eigen/src/Core/Reshaped.h +454 -0
- roboticstoolbox/core/Eigen/src/Core/ReturnByValue.h +119 -0
- roboticstoolbox/core/Eigen/src/Core/Reverse.h +217 -0
- roboticstoolbox/core/Eigen/src/Core/Select.h +164 -0
- roboticstoolbox/core/Eigen/src/Core/SelfAdjointView.h +365 -0
- roboticstoolbox/core/Eigen/src/Core/SelfCwiseBinaryOp.h +47 -0
- roboticstoolbox/core/Eigen/src/Core/Solve.h +188 -0
- roboticstoolbox/core/Eigen/src/Core/SolveTriangular.h +235 -0
- roboticstoolbox/core/Eigen/src/Core/SolverBase.h +168 -0
- roboticstoolbox/core/Eigen/src/Core/StableNorm.h +251 -0
- roboticstoolbox/core/Eigen/src/Core/StlIterators.h +463 -0
- roboticstoolbox/core/Eigen/src/Core/Stride.h +116 -0
- roboticstoolbox/core/Eigen/src/Core/Swap.h +68 -0
- roboticstoolbox/core/Eigen/src/Core/Transpose.h +464 -0
- roboticstoolbox/core/Eigen/src/Core/Transpositions.h +386 -0
- roboticstoolbox/core/Eigen/src/Core/TriangularMatrix.h +1001 -0
- roboticstoolbox/core/Eigen/src/Core/VectorBlock.h +96 -0
- roboticstoolbox/core/Eigen/src/Core/VectorwiseOp.h +784 -0
- roboticstoolbox/core/Eigen/src/Core/Visitor.h +381 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX/Complex.h +372 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX/MathFunctions.h +228 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX/PacketMath.h +1574 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX/TypeCasting.h +115 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX512/Complex.h +422 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX512/MathFunctions.h +362 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX512/PacketMath.h +2303 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AVX512/TypeCasting.h +89 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AltiVec/Complex.h +417 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AltiVec/MathFunctions.h +90 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AltiVec/MatrixProduct.h +2937 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AltiVec/MatrixProductCommon.h +221 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AltiVec/MatrixProductMMA.h +629 -0
- roboticstoolbox/core/Eigen/src/Core/arch/AltiVec/PacketMath.h +2711 -0
- roboticstoolbox/core/Eigen/src/Core/arch/CUDA/Complex.h +258 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/BFloat16.h +700 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/ConjHelper.h +117 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h +1649 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h +110 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/Half.h +942 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/Settings.h +49 -0
- roboticstoolbox/core/Eigen/src/Core/arch/Default/TypeCasting.h +120 -0
- roboticstoolbox/core/Eigen/src/Core/arch/GPU/MathFunctions.h +103 -0
- roboticstoolbox/core/Eigen/src/Core/arch/GPU/PacketMath.h +1685 -0
- roboticstoolbox/core/Eigen/src/Core/arch/GPU/TypeCasting.h +80 -0
- roboticstoolbox/core/Eigen/src/Core/arch/HIP/hcc/math_constants.h +23 -0
- roboticstoolbox/core/Eigen/src/Core/arch/MSA/Complex.h +648 -0
- roboticstoolbox/core/Eigen/src/Core/arch/MSA/MathFunctions.h +387 -0
- roboticstoolbox/core/Eigen/src/Core/arch/MSA/PacketMath.h +1233 -0
- roboticstoolbox/core/Eigen/src/Core/arch/NEON/Complex.h +584 -0
- roboticstoolbox/core/Eigen/src/Core/arch/NEON/GeneralBlockPanelKernel.h +183 -0
- roboticstoolbox/core/Eigen/src/Core/arch/NEON/MathFunctions.h +75 -0
- roboticstoolbox/core/Eigen/src/Core/arch/NEON/PacketMath.h +4587 -0
- roboticstoolbox/core/Eigen/src/Core/arch/NEON/TypeCasting.h +1419 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SSE/Complex.h +351 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SSE/MathFunctions.h +199 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SSE/PacketMath.h +1505 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SSE/TypeCasting.h +142 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SVE/MathFunctions.h +44 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SVE/PacketMath.h +752 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SVE/TypeCasting.h +49 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SYCL/InteropHeaders.h +232 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SYCL/MathFunctions.h +301 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SYCL/PacketMath.h +670 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SYCL/SyclMemoryModel.h +694 -0
- roboticstoolbox/core/Eigen/src/Core/arch/SYCL/TypeCasting.h +85 -0
- roboticstoolbox/core/Eigen/src/Core/arch/ZVector/Complex.h +426 -0
- roboticstoolbox/core/Eigen/src/Core/arch/ZVector/MathFunctions.h +233 -0
- roboticstoolbox/core/Eigen/src/Core/arch/ZVector/PacketMath.h +1060 -0
- roboticstoolbox/core/Eigen/src/Core/functors/AssignmentFunctors.h +177 -0
- roboticstoolbox/core/Eigen/src/Core/functors/BinaryFunctors.h +541 -0
- roboticstoolbox/core/Eigen/src/Core/functors/NullaryFunctors.h +189 -0
- roboticstoolbox/core/Eigen/src/Core/functors/StlFunctors.h +166 -0
- roboticstoolbox/core/Eigen/src/Core/functors/TernaryFunctors.h +25 -0
- roboticstoolbox/core/Eigen/src/Core/functors/UnaryFunctors.h +1131 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralBlockPanelKernel.h +2645 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralMatrixMatrix.h +517 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +317 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h +145 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h +124 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralMatrixVector.h +518 -0
- roboticstoolbox/core/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h +136 -0
- roboticstoolbox/core/Eigen/src/Core/products/Parallelizer.h +180 -0
- roboticstoolbox/core/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +544 -0
- roboticstoolbox/core/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h +295 -0
- roboticstoolbox/core/Eigen/src/Core/products/SelfadjointMatrixVector.h +262 -0
- roboticstoolbox/core/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h +118 -0
- roboticstoolbox/core/Eigen/src/Core/products/SelfadjointProduct.h +133 -0
- roboticstoolbox/core/Eigen/src/Core/products/SelfadjointRank2Update.h +94 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularMatrixMatrix.h +472 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h +317 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularMatrixVector.h +350 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h +255 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularSolverMatrix.h +337 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h +167 -0
- roboticstoolbox/core/Eigen/src/Core/products/TriangularSolverVector.h +148 -0
- roboticstoolbox/core/Eigen/src/Core/util/BlasUtil.h +583 -0
- roboticstoolbox/core/Eigen/src/Core/util/ConfigureVectorization.h +512 -0
- roboticstoolbox/core/Eigen/src/Core/util/Constants.h +563 -0
- roboticstoolbox/core/Eigen/src/Core/util/DisableStupidWarnings.h +106 -0
- roboticstoolbox/core/Eigen/src/Core/util/ForwardDeclarations.h +322 -0
- roboticstoolbox/core/Eigen/src/Core/util/IndexedViewHelper.h +186 -0
- roboticstoolbox/core/Eigen/src/Core/util/IntegralConstant.h +272 -0
- roboticstoolbox/core/Eigen/src/Core/util/MKL_support.h +137 -0
- roboticstoolbox/core/Eigen/src/Core/util/Macros.h +1464 -0
- roboticstoolbox/core/Eigen/src/Core/util/Memory.h +1163 -0
- roboticstoolbox/core/Eigen/src/Core/util/Meta.h +812 -0
- roboticstoolbox/core/Eigen/src/Core/util/NonMPL2.h +3 -0
- roboticstoolbox/core/Eigen/src/Core/util/ReenableStupidWarnings.h +31 -0
- roboticstoolbox/core/Eigen/src/Core/util/ReshapedHelper.h +51 -0
- roboticstoolbox/core/Eigen/src/Core/util/StaticAssert.h +221 -0
- roboticstoolbox/core/Eigen/src/Core/util/SymbolicIndex.h +293 -0
- roboticstoolbox/core/Eigen/src/Core/util/XprHelper.h +856 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/ComplexEigenSolver.h +346 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/ComplexSchur.h +462 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/ComplexSchur_LAPACKE.h +91 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/EigenSolver.h +622 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +418 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +226 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/HessenbergDecomposition.h +374 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +158 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/RealQZ.h +657 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/RealSchur.h +558 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/RealSchur_LAPACKE.h +77 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +904 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h +87 -0
- roboticstoolbox/core/Eigen/src/Eigenvalues/Tridiagonalization.h +561 -0
- roboticstoolbox/core/Eigen/src/Geometry/AlignedBox.h +486 -0
- roboticstoolbox/core/Eigen/src/Geometry/AngleAxis.h +247 -0
- roboticstoolbox/core/Eigen/src/Geometry/EulerAngles.h +114 -0
- roboticstoolbox/core/Eigen/src/Geometry/Homogeneous.h +501 -0
- roboticstoolbox/core/Eigen/src/Geometry/Hyperplane.h +282 -0
- roboticstoolbox/core/Eigen/src/Geometry/OrthoMethods.h +235 -0
- roboticstoolbox/core/Eigen/src/Geometry/ParametrizedLine.h +232 -0
- roboticstoolbox/core/Eigen/src/Geometry/Quaternion.h +870 -0
- roboticstoolbox/core/Eigen/src/Geometry/Rotation2D.h +199 -0
- roboticstoolbox/core/Eigen/src/Geometry/RotationBase.h +206 -0
- roboticstoolbox/core/Eigen/src/Geometry/Scaling.h +188 -0
- roboticstoolbox/core/Eigen/src/Geometry/Transform.h +1563 -0
- roboticstoolbox/core/Eigen/src/Geometry/Translation.h +202 -0
- roboticstoolbox/core/Eigen/src/Geometry/Umeyama.h +166 -0
- roboticstoolbox/core/Eigen/src/Geometry/arch/Geometry_SIMD.h +168 -0
- roboticstoolbox/core/Eigen/src/Householder/BlockHouseholder.h +110 -0
- roboticstoolbox/core/Eigen/src/Householder/Householder.h +176 -0
- roboticstoolbox/core/Eigen/src/Householder/HouseholderSequence.h +545 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +226 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +212 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +229 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h +394 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +453 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +444 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h +198 -0
- roboticstoolbox/core/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h +117 -0
- roboticstoolbox/core/Eigen/src/Jacobi/Jacobi.h +483 -0
- roboticstoolbox/core/Eigen/src/KLUSupport/KLUSupport.h +358 -0
- roboticstoolbox/core/Eigen/src/LU/Determinant.h +117 -0
- roboticstoolbox/core/Eigen/src/LU/FullPivLU.h +877 -0
- roboticstoolbox/core/Eigen/src/LU/InverseImpl.h +432 -0
- roboticstoolbox/core/Eigen/src/LU/PartialPivLU.h +624 -0
- roboticstoolbox/core/Eigen/src/LU/PartialPivLU_LAPACKE.h +83 -0
- roboticstoolbox/core/Eigen/src/LU/arch/InverseSize4.h +351 -0
- roboticstoolbox/core/Eigen/src/MetisSupport/MetisSupport.h +137 -0
- roboticstoolbox/core/Eigen/src/OrderingMethods/Amd.h +435 -0
- roboticstoolbox/core/Eigen/src/OrderingMethods/Eigen_Colamd.h +1863 -0
- roboticstoolbox/core/Eigen/src/OrderingMethods/Ordering.h +153 -0
- roboticstoolbox/core/Eigen/src/PaStiXSupport/PaStiXSupport.h +678 -0
- roboticstoolbox/core/Eigen/src/PardisoSupport/PardisoSupport.h +545 -0
- roboticstoolbox/core/Eigen/src/QR/ColPivHouseholderQR.h +674 -0
- roboticstoolbox/core/Eigen/src/QR/ColPivHouseholderQR_LAPACKE.h +97 -0
- roboticstoolbox/core/Eigen/src/QR/CompleteOrthogonalDecomposition.h +635 -0
- roboticstoolbox/core/Eigen/src/QR/FullPivHouseholderQR.h +713 -0
- roboticstoolbox/core/Eigen/src/QR/HouseholderQR.h +434 -0
- roboticstoolbox/core/Eigen/src/QR/HouseholderQR_LAPACKE.h +68 -0
- roboticstoolbox/core/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +335 -0
- roboticstoolbox/core/Eigen/src/SVD/BDCSVD.h +1366 -0
- roboticstoolbox/core/Eigen/src/SVD/JacobiSVD.h +812 -0
- roboticstoolbox/core/Eigen/src/SVD/JacobiSVD_LAPACKE.h +91 -0
- roboticstoolbox/core/Eigen/src/SVD/SVDBase.h +376 -0
- roboticstoolbox/core/Eigen/src/SVD/UpperBidiagonalization.h +414 -0
- roboticstoolbox/core/Eigen/src/SparseCholesky/SimplicialCholesky.h +697 -0
- roboticstoolbox/core/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h +174 -0
- roboticstoolbox/core/Eigen/src/SparseCore/AmbiVector.h +378 -0
- roboticstoolbox/core/Eigen/src/SparseCore/CompressedStorage.h +274 -0
- roboticstoolbox/core/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +352 -0
- roboticstoolbox/core/Eigen/src/SparseCore/MappedSparseMatrix.h +67 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseAssign.h +270 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseBlock.h +571 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseColEtree.h +206 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseCompressedBase.h +370 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +722 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +150 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseDenseProduct.h +342 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseDiagonalProduct.h +138 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseDot.h +98 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseFuzzy.h +29 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseMap.h +305 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseMatrix.h +1518 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseMatrixBase.h +398 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparsePermutation.h +178 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseProduct.h +181 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseRedux.h +49 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseRef.h +397 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseSelfAdjointView.h +659 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseSolverBase.h +124 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +198 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseTranspose.h +92 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseTriangularView.h +189 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseUtil.h +186 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseVector.h +478 -0
- roboticstoolbox/core/Eigen/src/SparseCore/SparseView.h +254 -0
- roboticstoolbox/core/Eigen/src/SparseCore/TriangularSolver.h +315 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU.h +923 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLUImpl.h +66 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_Memory.h +226 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_Structs.h +110 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +375 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_Utils.h +80 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_column_bmod.h +181 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_column_dfs.h +179 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_copy_to_ucol.h +107 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_gemm_kernel.h +280 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h +126 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_kernel_bmod.h +130 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_panel_bmod.h +223 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_panel_dfs.h +258 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_pivotL.h +137 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_pruneL.h +136 -0
- roboticstoolbox/core/Eigen/src/SparseLU/SparseLU_relax_snode.h +83 -0
- roboticstoolbox/core/Eigen/src/SparseQR/SparseQR.h +758 -0
- roboticstoolbox/core/Eigen/src/StlSupport/StdDeque.h +116 -0
- roboticstoolbox/core/Eigen/src/StlSupport/StdList.h +106 -0
- roboticstoolbox/core/Eigen/src/StlSupport/StdVector.h +131 -0
- roboticstoolbox/core/Eigen/src/StlSupport/details.h +84 -0
- roboticstoolbox/core/Eigen/src/SuperLUSupport/SuperLUSupport.h +1025 -0
- roboticstoolbox/core/Eigen/src/UmfPackSupport/UmfPackSupport.h +642 -0
- roboticstoolbox/core/Eigen/src/misc/Image.h +82 -0
- roboticstoolbox/core/Eigen/src/misc/Kernel.h +79 -0
- roboticstoolbox/core/Eigen/src/misc/RealSvd2x2.h +55 -0
- roboticstoolbox/core/Eigen/src/misc/blas.h +440 -0
- roboticstoolbox/core/Eigen/src/misc/lapack.h +152 -0
- roboticstoolbox/core/Eigen/src/misc/lapacke.h +16292 -0
- roboticstoolbox/core/Eigen/src/misc/lapacke_mangling.h +17 -0
- roboticstoolbox/core/Eigen/src/plugins/ArrayCwiseBinaryOps.h +358 -0
- roboticstoolbox/core/Eigen/src/plugins/ArrayCwiseUnaryOps.h +696 -0
- roboticstoolbox/core/Eigen/src/plugins/BlockMethods.h +1442 -0
- roboticstoolbox/core/Eigen/src/plugins/CommonCwiseBinaryOps.h +115 -0
- roboticstoolbox/core/Eigen/src/plugins/CommonCwiseUnaryOps.h +177 -0
- roboticstoolbox/core/Eigen/src/plugins/IndexedViewMethods.h +262 -0
- roboticstoolbox/core/Eigen/src/plugins/MatrixCwiseBinaryOps.h +152 -0
- roboticstoolbox/core/Eigen/src/plugins/MatrixCwiseUnaryOps.h +95 -0
- roboticstoolbox/core/Eigen/src/plugins/ReshapedMethods.h +149 -0
- roboticstoolbox/core/fknm.cpp +1557 -0
- roboticstoolbox/core/fknm.h +55 -0
- roboticstoolbox/core/frne.c +351 -0
- roboticstoolbox/core/frne.h +96 -0
- roboticstoolbox/core/ik.cpp +301 -0
- roboticstoolbox/core/ik.h +59 -0
- roboticstoolbox/core/linalg.cpp +316 -0
- roboticstoolbox/core/linalg.h +64 -0
- roboticstoolbox/core/methods.cpp +372 -0
- roboticstoolbox/core/methods.h +32 -0
- roboticstoolbox/core/ne.c +493 -0
- roboticstoolbox/core/structs.cpp +24 -0
- roboticstoolbox/core/structs.h +62 -0
- roboticstoolbox/core/vmath.c +163 -0
- roboticstoolbox/core/vmath.h +32 -0
- roboticstoolbox/fknm.cp312-win_amd64.pyd +0 -0
- roboticstoolbox/frne.cp312-win_amd64.pyd +0 -0
- roboticstoolbox/mobile/Animations.py +485 -0
- roboticstoolbox/mobile/Bug2.py +455 -0
- roboticstoolbox/mobile/CurvaturePolyPlanner.py +179 -0
- roboticstoolbox/mobile/DistanceTransformPlanner.py +395 -0
- roboticstoolbox/mobile/DstarPlanner.py +591 -0
- roboticstoolbox/mobile/DubinsPlanner.py +474 -0
- roboticstoolbox/mobile/EKF.py +1617 -0
- roboticstoolbox/mobile/LatticePlanner.py +419 -0
- roboticstoolbox/mobile/OccGrid.py +613 -0
- roboticstoolbox/mobile/PRMPlanner.py +348 -0
- roboticstoolbox/mobile/ParticleFilter.py +706 -0
- roboticstoolbox/mobile/PlannerBase.py +1009 -0
- roboticstoolbox/mobile/PoseGraph.py +544 -0
- roboticstoolbox/mobile/QuinticPolyPlanner.py +349 -0
- roboticstoolbox/mobile/RRTPlanner.py +359 -0
- roboticstoolbox/mobile/ReedsSheppPlanner.py +545 -0
- roboticstoolbox/mobile/Vehicle.py +1909 -0
- roboticstoolbox/mobile/__init__.py +193 -0
- roboticstoolbox/mobile/drivers.py +390 -0
- roboticstoolbox/mobile/landmarkmap.py +181 -0
- roboticstoolbox/mobile/sensors.py +771 -0
- roboticstoolbox/models/DH/AL5D.py +121 -0
- roboticstoolbox/models/DH/Ball.py +87 -0
- roboticstoolbox/models/DH/Baxter.py +91 -0
- roboticstoolbox/models/DH/Cobra600.py +63 -0
- roboticstoolbox/models/DH/Coil.py +80 -0
- roboticstoolbox/models/DH/Hyper.py +83 -0
- roboticstoolbox/models/DH/Hyper3d.py +85 -0
- roboticstoolbox/models/DH/IRB140.py +159 -0
- roboticstoolbox/models/DH/Jaco.py +102 -0
- roboticstoolbox/models/DH/KR5.py +112 -0
- roboticstoolbox/models/DH/LWR4.py +85 -0
- roboticstoolbox/models/DH/Mico.py +102 -0
- roboticstoolbox/models/DH/Orion5.py +91 -0
- roboticstoolbox/models/DH/P8.py +80 -0
- roboticstoolbox/models/DH/Panda.py +178 -0
- roboticstoolbox/models/DH/Planar2.py +69 -0
- roboticstoolbox/models/DH/Planar3.py +51 -0
- roboticstoolbox/models/DH/Puma560.py +326 -0
- roboticstoolbox/models/DH/README.md +216 -0
- roboticstoolbox/models/DH/Sawyer.py +85 -0
- roboticstoolbox/models/DH/Stanford.py +147 -0
- roboticstoolbox/models/DH/TwoLink.py +109 -0
- roboticstoolbox/models/DH/UR10.py +124 -0
- roboticstoolbox/models/DH/UR3.py +98 -0
- roboticstoolbox/models/DH/UR5.py +98 -0
- roboticstoolbox/models/DH/Uprighttl.py +24 -0
- roboticstoolbox/models/DH/__init__.py +52 -0
- roboticstoolbox/models/ETS/Frankie.py +90 -0
- roboticstoolbox/models/ETS/GenericSeven.py +54 -0
- roboticstoolbox/models/ETS/Omni.py +74 -0
- roboticstoolbox/models/ETS/Panda.py +69 -0
- roboticstoolbox/models/ETS/Planar2.py +49 -0
- roboticstoolbox/models/ETS/Planar_Y.py +65 -0
- roboticstoolbox/models/ETS/Puma560.py +69 -0
- roboticstoolbox/models/ETS/XYPanda.py +84 -0
- roboticstoolbox/models/ETS/__init__.py +20 -0
- roboticstoolbox/models/README.md +9 -0
- roboticstoolbox/models/URDF/AL5D.py +54 -0
- roboticstoolbox/models/URDF/Fetch.py +70 -0
- roboticstoolbox/models/URDF/FetchCamera.py +71 -0
- roboticstoolbox/models/URDF/Frankie.py +75 -0
- roboticstoolbox/models/URDF/FrankieOmni.py +94 -0
- roboticstoolbox/models/URDF/KinovaGen3.py +71 -0
- roboticstoolbox/models/URDF/LBR.py +59 -0
- roboticstoolbox/models/URDF/Mico.py +68 -0
- roboticstoolbox/models/URDF/PR2.py +64 -0
- roboticstoolbox/models/URDF/Panda.py +67 -0
- roboticstoolbox/models/URDF/Puma560.py +97 -0
- roboticstoolbox/models/URDF/UR10.py +53 -0
- roboticstoolbox/models/URDF/UR3.py +53 -0
- roboticstoolbox/models/URDF/UR5.py +74 -0
- roboticstoolbox/models/URDF/Valkyrie.py +84 -0
- roboticstoolbox/models/URDF/YuMi.py +109 -0
- roboticstoolbox/models/URDF/__init__.py +53 -0
- roboticstoolbox/models/URDF/px100.py +56 -0
- roboticstoolbox/models/URDF/px150.py +56 -0
- roboticstoolbox/models/URDF/rx150.py +56 -0
- roboticstoolbox/models/URDF/rx200.py +56 -0
- roboticstoolbox/models/URDF/vx300.py +56 -0
- roboticstoolbox/models/URDF/vx300s.py +56 -0
- roboticstoolbox/models/URDF/wx200.py +56 -0
- roboticstoolbox/models/URDF/wx250.py +56 -0
- roboticstoolbox/models/URDF/wx250s.py +56 -0
- roboticstoolbox/models/__init__.py +7 -0
- roboticstoolbox/models/list.py +119 -0
- roboticstoolbox/robot/BaseRobot.py +3133 -0
- roboticstoolbox/robot/DHFactor.py +522 -0
- roboticstoolbox/robot/DHLink.py +981 -0
- roboticstoolbox/robot/DHRobot.py +2520 -0
- roboticstoolbox/robot/Dynamics.py +1620 -0
- roboticstoolbox/robot/ELink.py +23 -0
- roboticstoolbox/robot/ERobot.py +25 -0
- roboticstoolbox/robot/ET.py +1097 -0
- roboticstoolbox/robot/ETS.py +3542 -0
- roboticstoolbox/robot/Gripper.py +282 -0
- roboticstoolbox/robot/IK.py +1522 -0
- roboticstoolbox/robot/Link.py +1698 -0
- roboticstoolbox/robot/PoERobot.py +348 -0
- roboticstoolbox/robot/Robot.py +2100 -0
- roboticstoolbox/robot/RobotKinematics.py +1725 -0
- roboticstoolbox/robot/RobotProto.py +92 -0
- roboticstoolbox/robot/__init__.py +54 -0
- roboticstoolbox/tools/DHFactor.py +375 -0
- roboticstoolbox/tools/Ticker.py +53 -0
- roboticstoolbox/tools/__init__.py +54 -0
- roboticstoolbox/tools/data.py +187 -0
- roboticstoolbox/tools/jsingu.py +51 -0
- roboticstoolbox/tools/null.py +48 -0
- roboticstoolbox/tools/numerical.py +96 -0
- roboticstoolbox/tools/p_servo.py +106 -0
- roboticstoolbox/tools/params.py +11 -0
- roboticstoolbox/tools/plot.py +109 -0
- roboticstoolbox/tools/trajectory.py +1152 -0
- roboticstoolbox/tools/types.py +13 -0
- roboticstoolbox/tools/urdf/__init__.py +45 -0
- roboticstoolbox/tools/urdf/tests/data/ur5.urdf +341 -0
- roboticstoolbox/tools/urdf/tests/test_urdf.py +116 -0
- roboticstoolbox/tools/urdf/urdf.py +1976 -0
- roboticstoolbox/tools/urdf/utils.py +50 -0
- roboticstoolbox/tools/xacro/__init__.py +1148 -0
- roboticstoolbox/tools/xacro/cli.py +128 -0
- roboticstoolbox/tools/xacro/color.py +66 -0
- roboticstoolbox/tools/xacro/tests/CMakeLists.txt +4 -0
- roboticstoolbox/tools/xacro/tests/broken.xacro +1 -0
- roboticstoolbox/tools/xacro/tests/emoji.xacro +5 -0
- roboticstoolbox/tools/xacro/tests/include1.xacro +4 -0
- roboticstoolbox/tools/xacro/tests/include1.xml +1 -0
- roboticstoolbox/tools/xacro/tests/include2.xacro +4 -0
- roboticstoolbox/tools/xacro/tests/include2.xml +1 -0
- roboticstoolbox/tools/xacro/tests/robots/README +4 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/base_v0/base.gazebo.xacro +59 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/base_v0/base.transmission.xacro +24 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/base_v0/base.urdf.xacro +264 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/common.xacro +71 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/forearm_v0/forearm.gazebo.xacro +36 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/forearm_v0/forearm.transmission.xacro +20 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/forearm_v0/forearm.urdf.xacro +130 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/gazebo/gazebo.urdf.xacro +24 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/gripper_v0/gripper.gazebo.xacro +288 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/gripper_v0/gripper.transmission.xacro +50 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/gripper_v0/gripper.urdf.xacro +374 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/head_v0/head.gazebo.xacro +16 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/head_v0/head.transmission.xacro +34 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/head_v0/head.urdf.xacro +147 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/materials.urdf.xacro +52 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/pr2.urdf.xacro +157 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/pr2_1.11.4.xml +3781 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/double_stereo_camera.gazebo.xacro +16 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/double_stereo_camera.urdf.xacro +61 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/head_sensor_package.gazebo.xacro +20 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/head_sensor_package.urdf.xacro +63 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/hokuyo_lx30_laser.gazebo.xacro +39 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/hokuyo_lx30_laser.urdf.xacro +27 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/kinect_camera.gazebo.xacro +87 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/kinect_camera.urdf.xacro +55 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/kinect_prosilica_camera.gazebo.xacro +193 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/kinect_prosilica_camera.urdf.xacro +181 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/microstrain_3dmgx2_imu.gazebo.xacro +20 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/microstrain_3dmgx2_imu.urdf.xacro +25 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/projector_wg6802418.gazebo.xacro +31 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/projector_wg6802418.urdf.xacro +42 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/prosilica_gc2450_camera.gazebo.xacro +43 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/prosilica_gc2450_camera.urdf.xacro +49 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/stereo_camera.gazebo.xacro +23 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/stereo_camera.urdf.xacro +71 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/wge100_camera.gazebo.xacro +46 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/sensors/wge100_camera.urdf.xacro +47 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/shoulder_v0/shoulder.gazebo.xacro +40 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/shoulder_v0/shoulder.transmission.xacro +35 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/shoulder_v0/shoulder.urdf.xacro +167 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/tilting_laser_v0/tilting_laser.gazebo.xacro +11 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/tilting_laser_v0/tilting_laser.transmission.xacro +14 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/tilting_laser_v0/tilting_laser.urdf.xacro +60 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/torso_v0/torso.gazebo.xacro +37 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/torso_v0/torso.transmission.xacro +22 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/torso_v0/torso.urdf.xacro +122 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/upper_arm_v0/upper_arm.gazebo.xacro +39 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/upper_arm_v0/upper_arm.transmission.xacro +28 -0
- roboticstoolbox/tools/xacro/tests/robots/pr2/upper_arm_v0/upper_arm.urdf.xacro +173 -0
- roboticstoolbox/tools/xacro/tests/settings.yaml +9 -0
- roboticstoolbox/tools/xacro/tests/subdir/foo.xacro +3 -0
- roboticstoolbox/tools/xacro/tests/subdir/include-recursive.xacro +5 -0
- roboticstoolbox/tools/xacro/tests/subdir/include1.xml +1 -0
- roboticstoolbox/tools/xacro/tests/test_xacro.py +1418 -0
- roboticstoolbox/tools/xacro/xmlutils.py +152 -0
- roboticstoolbox_python-1.3.0.dist-info/METADATA +552 -0
- roboticstoolbox_python-1.3.0.dist-info/RECORD +673 -0
- roboticstoolbox_python-1.3.0.dist-info/WHEEL +5 -0
- roboticstoolbox_python-1.3.0.dist-info/entry_points.txt +6 -0
- roboticstoolbox_python-1.3.0.dist-info/licenses/LICENSE +21 -0
- spatialgeometry/__init__.py +32 -0
- spatialgeometry/geom/CollisionShape.py +419 -0
- spatialgeometry/geom/SceneGroup.py +26 -0
- spatialgeometry/geom/SceneNode.py +315 -0
- spatialgeometry/geom/Shape.py +420 -0
- spatialgeometry/geom/__init__.py +26 -0
- spatialgeometry/scene.py +107 -0
- spatialgeometry/tools/__init__.py +0 -0
- spatialgeometry/tools/stdout_supress.py +302 -0
|
@@ -0,0 +1,1617 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python EKF Planner
|
|
3
|
+
@Author: Peter Corke, original MATLAB code and Python version
|
|
4
|
+
@Author: Kristian Gibson, initial MATLAB port
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections import namedtuple
|
|
8
|
+
import numpy as np
|
|
9
|
+
from scipy.linalg import block_diag
|
|
10
|
+
from scipy.stats.distributions import chi2
|
|
11
|
+
import matplotlib.pyplot as plt
|
|
12
|
+
from matplotlib import animation
|
|
13
|
+
|
|
14
|
+
from spatialmath import base, SE2
|
|
15
|
+
from roboticstoolbox.mobile import VehicleBase
|
|
16
|
+
from roboticstoolbox.mobile.landmarkmap import LandmarkMap
|
|
17
|
+
from roboticstoolbox.mobile.sensors import SensorBase
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EKF:
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
robot,
|
|
24
|
+
sensor=None,
|
|
25
|
+
map=None,
|
|
26
|
+
P0=None,
|
|
27
|
+
x_est=None,
|
|
28
|
+
joseph=True,
|
|
29
|
+
animate=True,
|
|
30
|
+
x0=[0, 0, 0],
|
|
31
|
+
verbose=False,
|
|
32
|
+
history=True,
|
|
33
|
+
workspace=None,
|
|
34
|
+
):
|
|
35
|
+
r"""
|
|
36
|
+
Extended Kalman filter
|
|
37
|
+
|
|
38
|
+
:param robot: robot motion model
|
|
39
|
+
:type robot: 2-tuple
|
|
40
|
+
:param sensor: vehicle mounted sensor model, defaults to None
|
|
41
|
+
:type sensor: 2-tuple, optional
|
|
42
|
+
:param map: landmark map, defaults to None
|
|
43
|
+
:type map: :class:`LandmarkMap`, optional
|
|
44
|
+
:param P0: initial covariance matrix, defaults to None
|
|
45
|
+
:type P0: ndarray(n,n), optional
|
|
46
|
+
:param x_est: initial state estimate, defaults to None
|
|
47
|
+
:type x_est: array_like(n), optional
|
|
48
|
+
:param joseph: use Joseph update of covariance, defaults to True
|
|
49
|
+
:type joseph: bool, optional
|
|
50
|
+
:param animate: show animation of vehicle motion, defaults to True
|
|
51
|
+
:type animate: bool, optional
|
|
52
|
+
:param x0: initial EKF state, defaults to [0, 0, 0]
|
|
53
|
+
:type x0: array_like(n), optional
|
|
54
|
+
:param verbose: display extra debug information, defaults to False
|
|
55
|
+
:type verbose: bool, optional
|
|
56
|
+
:param history: retain step-by-step history, defaults to True
|
|
57
|
+
:type history: bool, optional
|
|
58
|
+
:param workspace: dimension of workspace, see :func:`~spatialmath.base.graphics.expand_dims`
|
|
59
|
+
:type workspace: scalar, array_like(2), array_like(4)
|
|
60
|
+
|
|
61
|
+
This class solves several classical robotic estimation problems, which are
|
|
62
|
+
selected according to the arguments:
|
|
63
|
+
|
|
64
|
+
====================== ====== ========== ========== ======= ======
|
|
65
|
+
Problem len(x) ``robot`` ``sensor`` ``map`` ``P0``
|
|
66
|
+
====================== ====== ========== ========== ======= ======
|
|
67
|
+
Dead reckoning 3 (veh,V) None None P0
|
|
68
|
+
Map-based localization 3 (veh,V) (smodel,W) yes P0
|
|
69
|
+
Map creation 2N (veh,None) (smodel,W) None None
|
|
70
|
+
SLAM 3+2N (veh,V) (smodel,W) None P0
|
|
71
|
+
====================== ====== ========== ========== ======= ======
|
|
72
|
+
|
|
73
|
+
where:
|
|
74
|
+
|
|
75
|
+
- ``veh`` models the robotic vehicle kinematics and odometry and is a :class:`VehicleBase` subclass
|
|
76
|
+
- ``V`` is the estimated odometry (process) noise covariance as an ndarray(3,3)
|
|
77
|
+
- ``smodel`` models the robot mounted sensor and is a :class:`SensorBase` subclass
|
|
78
|
+
- ``W`` is the estimated sensor (measurement) noise covariance as an ndarray(2,2)
|
|
79
|
+
|
|
80
|
+
The state vector has different lengths depending on the particular
|
|
81
|
+
estimation problem, see below.
|
|
82
|
+
|
|
83
|
+
At each iteration of the EKF:
|
|
84
|
+
|
|
85
|
+
- invoke the step method of the ``robot``
|
|
86
|
+
|
|
87
|
+
- obtains the next control input from the driver agent, and apply it
|
|
88
|
+
as the vehicle control input
|
|
89
|
+
- the vehicle returns a noisy odometry estimate
|
|
90
|
+
|
|
91
|
+
- the state prediction is computed
|
|
92
|
+
- the true pose is used to determine a noisy sensor observation
|
|
93
|
+
- the state is corrected, new landmarks are added to the map
|
|
94
|
+
|
|
95
|
+
The working area of the robot is defined by ``workspace`` or inherited
|
|
96
|
+
from the landmark map attached to the ``sensor`` (see
|
|
97
|
+
:func:`~spatialmath.base.graphics.expand_dims`):
|
|
98
|
+
|
|
99
|
+
============== ======= =======
|
|
100
|
+
``workspace`` x-range y-range
|
|
101
|
+
============== ======= =======
|
|
102
|
+
A (scalar) -A:A -A:A
|
|
103
|
+
[A, B] A:B A:B
|
|
104
|
+
[A, B, C, D] A:B C:D
|
|
105
|
+
============== ======= =======
|
|
106
|
+
|
|
107
|
+
**Dead-reckoning localization**
|
|
108
|
+
|
|
109
|
+
The state :math:`\vec{x} = (x, y, \theta)` is the estimated vehicle
|
|
110
|
+
configuration.
|
|
111
|
+
|
|
112
|
+
Create a vehicle with odometry covariance ``V``, add a driver to it,
|
|
113
|
+
run the Kalman filter with estimated covariances ``V`` and initial
|
|
114
|
+
vehicle state covariance ``P0``::
|
|
115
|
+
|
|
116
|
+
V = np.diag([0.02, np.radians(0.5)]) ** 2;
|
|
117
|
+
robot = Bicycle(covar=V)
|
|
118
|
+
robot.control = RandomPath(workspace=10)
|
|
119
|
+
|
|
120
|
+
x_sdev = [0.05, 0.05, np.radians(0.5)]
|
|
121
|
+
P0 = np.diag(x_sdev) ** 2
|
|
122
|
+
ekf = EKF(robot=(robot, V), P0=P0)
|
|
123
|
+
|
|
124
|
+
ekf.run(T=20) # run the simulation for 20 seconds
|
|
125
|
+
|
|
126
|
+
robot.plot_xy(color="b") # plot the true vehicle path
|
|
127
|
+
ekf.plot_xy(color="r") # overlay the estimated path
|
|
128
|
+
ekf.plot_ellipse(filled=True, facecolor="g", alpha=0.3) # overlay uncertainty ellipses
|
|
129
|
+
|
|
130
|
+
# plot the covariance against time
|
|
131
|
+
t = ekf.get_t();
|
|
132
|
+
pn = ekf.get_Pnorm()
|
|
133
|
+
plt.plot(t, pn);
|
|
134
|
+
|
|
135
|
+
**Map-based vehicle localization**
|
|
136
|
+
|
|
137
|
+
The state :math:`\vec{x} = (x, y, \theta)` is the estimated vehicle
|
|
138
|
+
configuration.
|
|
139
|
+
|
|
140
|
+
Create a vehicle with odometry covariance ``V``, add a driver to it,
|
|
141
|
+
create a map with 20 point landmarks, create a sensor that uses the map
|
|
142
|
+
and vehicle state to estimate landmark range and bearing with covariance
|
|
143
|
+
``W``, the Kalman filter with estimated covariances ``V`` and ``W`` and
|
|
144
|
+
initial vehicle state covariance ``P0``::
|
|
145
|
+
|
|
146
|
+
V = np.diag([0.02, np.radians(0.5)]) ** 2;
|
|
147
|
+
robot = Bicycle(covar=V)
|
|
148
|
+
robot.control = RandomPath(workspace=10)
|
|
149
|
+
|
|
150
|
+
map = LandmarkMap(nlandmarks=20, workspace=10)
|
|
151
|
+
|
|
152
|
+
W = np.diag([0.1, np.radians(1)]) ** 2
|
|
153
|
+
sensor = RangeBearingSensor(robot=robot, map=map, covar=W, angle=[-np.pi/2, np.pi/2], range=4, animate=True)
|
|
154
|
+
|
|
155
|
+
x_sdev = [0.05, 0.05, np.radians(0.5)]
|
|
156
|
+
P0 = np.diag(x_sdev) ** 2
|
|
157
|
+
ekf = EKF(robot=(robot, V), P0=P0, map=map, sensor=(sensor, W))
|
|
158
|
+
|
|
159
|
+
ekf.run(T=20) # run the simulation for 20 seconds
|
|
160
|
+
|
|
161
|
+
map.plot() # plot the map
|
|
162
|
+
robot.plot_xy(color="b") # plot the true vehicle path
|
|
163
|
+
ekf.plot_xy(color="r") # overlay the estimated path
|
|
164
|
+
ekf.plot_ellipse() # overlay uncertainty ellipses
|
|
165
|
+
|
|
166
|
+
# plot the covariance against time
|
|
167
|
+
t = ekf.get_t();
|
|
168
|
+
pn = ekf.get_Pnorm()
|
|
169
|
+
plt.plot(t, pn);
|
|
170
|
+
|
|
171
|
+
**Vehicle-based map making**
|
|
172
|
+
|
|
173
|
+
The state :math:`\vec{x} = (x_0, y_0, \dots, x_{N-1}, y_{N-1})` is the
|
|
174
|
+
estimated landmark positions where :math:`N` is the number of landmarks.
|
|
175
|
+
The state vector is initially empty, and is extended by 2 elements every
|
|
176
|
+
time a new landmark is observed.
|
|
177
|
+
|
|
178
|
+
Create a vehicle with perfect odometry (no covariance), add a driver to it,
|
|
179
|
+
create a sensor that uses the map and vehicle state to estimate landmark range
|
|
180
|
+
and bearing with covariance ``W``, the Kalman filter with estimated sensor
|
|
181
|
+
covariance ``W``, then run the filter for N time steps::
|
|
182
|
+
|
|
183
|
+
robot = Bicycle()
|
|
184
|
+
robot.add_driver(RandomPath(20, 2))
|
|
185
|
+
|
|
186
|
+
map = LandmarkMap(nlandmarks=20, workspace=10, seed=0)
|
|
187
|
+
|
|
188
|
+
W = np.diag([0.1, np.radians(1)]) ** 2
|
|
189
|
+
sensor = RangeBearingSensor(robot, map, W)
|
|
190
|
+
|
|
191
|
+
ekf = EKF(robot=(robot, None), sensor=(sensor, W))
|
|
192
|
+
|
|
193
|
+
ekf.run(T=20) # run the simulation for 20 seconds
|
|
194
|
+
|
|
195
|
+
map.plot() # plot the map
|
|
196
|
+
robot.plot_xy(color="b") # plot the true vehicle path
|
|
197
|
+
|
|
198
|
+
**Simultaneous localization and mapping (SLAM)**
|
|
199
|
+
|
|
200
|
+
The state :math:`\vec{x} = (x, y, \theta, x_0, y_0, \dots, x_{N-1},
|
|
201
|
+
y_{N-1})` is the estimated vehicle configuration followed by the
|
|
202
|
+
estimated landmark positions where :math:`N` is the number of landmarks.
|
|
203
|
+
The state vector is initially of length 3, and is extended by 2 elements
|
|
204
|
+
every time a new landmark is observed.
|
|
205
|
+
|
|
206
|
+
Create a vehicle with odometry covariance ``V``, add a driver to it,
|
|
207
|
+
create a map with 20 point landmarks, create a sensor that uses the map
|
|
208
|
+
and vehicle state to estimate landmark range and bearing with covariance
|
|
209
|
+
``W``, the Kalman filter with estimated covariances ``V`` and ``W`` and
|
|
210
|
+
initial state covariance ``P0``, then run the filter to estimate the
|
|
211
|
+
vehicle state at each time step and the map::
|
|
212
|
+
|
|
213
|
+
V = np.diag([0.02, np.radians(0.5)]) ** 2;
|
|
214
|
+
robot = Bicycle(covar=V)
|
|
215
|
+
robot.control = RandomPath(workspace=10)
|
|
216
|
+
|
|
217
|
+
map = LandmarkMap(nlandmarks=20, workspace=10)
|
|
218
|
+
|
|
219
|
+
W = np.diag([0.1, np.radians(1)]) ** 2
|
|
220
|
+
sensor = RangeBearingSensor(robot=robot, map=map, covar=W, angle=[-np.pi/2, np.pi/2], range=4, animate=True)
|
|
221
|
+
|
|
222
|
+
ekf = EKF(robot=(robot, V), P0=P0, sensor=(sensor, W))
|
|
223
|
+
|
|
224
|
+
ekf.run(T=20) # run the simulation for 20 seconds
|
|
225
|
+
|
|
226
|
+
map.plot(); # plot true map
|
|
227
|
+
ekf.plot_map(); # plot estimated landmark position
|
|
228
|
+
|
|
229
|
+
robot.plot_xy(); # plot true path
|
|
230
|
+
ekf.plot_xy(); # plot estimated robot path
|
|
231
|
+
ekf.plot_ellipse(); # plot estimated covariance
|
|
232
|
+
|
|
233
|
+
# plot the covariance against time
|
|
234
|
+
t = ekf.get_t();
|
|
235
|
+
pn = ekf.get_Pnorm()
|
|
236
|
+
plt.plot(t, pn);
|
|
237
|
+
|
|
238
|
+
:seealso: :meth:`run`
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
if robot is not None:
|
|
242
|
+
if (
|
|
243
|
+
not isinstance(robot, tuple)
|
|
244
|
+
or len(robot) != 2
|
|
245
|
+
or not isinstance(robot[0], VehicleBase)
|
|
246
|
+
):
|
|
247
|
+
raise TypeError("robot must be tuple (vehicle, V_est)")
|
|
248
|
+
self._robot = robot[0] # reference to the robot vehicle
|
|
249
|
+
self._V_est = robot[1] # estimate of vehicle state covariance V
|
|
250
|
+
|
|
251
|
+
if sensor is not None:
|
|
252
|
+
if (
|
|
253
|
+
not isinstance(sensor, tuple)
|
|
254
|
+
or len(sensor) != 2
|
|
255
|
+
or not isinstance(sensor[0], SensorBase)
|
|
256
|
+
):
|
|
257
|
+
raise TypeError("sensor must be tuple (sensor, W_est)")
|
|
258
|
+
self._sensor = sensor[0] # reference to the sensor
|
|
259
|
+
self._W_est = sensor[1] # estimate of sensor covariance W
|
|
260
|
+
else:
|
|
261
|
+
self._sensor = None
|
|
262
|
+
self._W_est = None
|
|
263
|
+
|
|
264
|
+
if map is not None and not isinstance(map, LandmarkMap):
|
|
265
|
+
raise TypeError("map must be LandmarkMap instance")
|
|
266
|
+
self._ekf_map = map # prior map for localization
|
|
267
|
+
|
|
268
|
+
if animate:
|
|
269
|
+
if map is not None:
|
|
270
|
+
self._workspace = map.workspace
|
|
271
|
+
self._robot._workspace = map.workspace
|
|
272
|
+
elif sensor is not None:
|
|
273
|
+
self._workspace = sensor[0].map.workspace
|
|
274
|
+
self._robot._workspace = sensor[0].map.workspace
|
|
275
|
+
elif self.robot.workspace is None:
|
|
276
|
+
raise ValueError("for animation robot must have a defined workspace")
|
|
277
|
+
self.animate = animate
|
|
278
|
+
|
|
279
|
+
self._P0 = P0 # initial system covariance
|
|
280
|
+
self._x0 = x0 # initial vehicle state
|
|
281
|
+
|
|
282
|
+
self._x_est = x_est # estimated state
|
|
283
|
+
self._landmarks = None # ekf_map state
|
|
284
|
+
|
|
285
|
+
self._est_vehicle = False
|
|
286
|
+
self._est_ekf_map = False
|
|
287
|
+
if self._V_est is not None:
|
|
288
|
+
# estimating vehicle pose by:
|
|
289
|
+
# - DR if sensor is None
|
|
290
|
+
# - localization if sensor is not None and map is not None
|
|
291
|
+
self._est_vehicle = True
|
|
292
|
+
|
|
293
|
+
# perfect vehicle case
|
|
294
|
+
if map is None and sensor is not None:
|
|
295
|
+
# estimating ekf_map
|
|
296
|
+
self._est_ekf_map = True
|
|
297
|
+
self._joseph = joseph # flag: use Joseph form to compute p
|
|
298
|
+
|
|
299
|
+
self._verbose = verbose
|
|
300
|
+
|
|
301
|
+
self._keep_history = history # keep history
|
|
302
|
+
self._htuple = namedtuple("EKFlog", "t xest odo P innov S K lm z")
|
|
303
|
+
|
|
304
|
+
if workspace is not None:
|
|
305
|
+
self._dim = base.expand_dims(dim)
|
|
306
|
+
elif self.sensor is not None:
|
|
307
|
+
self._dim = self.sensor.map.workspace
|
|
308
|
+
else:
|
|
309
|
+
self._dim = self._robot.workspace
|
|
310
|
+
|
|
311
|
+
# self.robot.init()
|
|
312
|
+
|
|
313
|
+
# # clear the history
|
|
314
|
+
# self._history = []
|
|
315
|
+
|
|
316
|
+
if self.V_est is None:
|
|
317
|
+
# perfect vehicle case
|
|
318
|
+
|
|
319
|
+
self._est_vehicle = False
|
|
320
|
+
self._x_est = None
|
|
321
|
+
self._P_est = None
|
|
322
|
+
else:
|
|
323
|
+
# noisy odometry case
|
|
324
|
+
if self.V_est.shape != (2, 2):
|
|
325
|
+
raise ValueError("vehicle state covariance V_est must be 2x2")
|
|
326
|
+
self._x_est = self.robot.x
|
|
327
|
+
self._P_est = P0
|
|
328
|
+
self._est_vehicle = True
|
|
329
|
+
|
|
330
|
+
if self.W_est is not None:
|
|
331
|
+
if self.W_est.shape != (2, 2):
|
|
332
|
+
raise ValueError("sensor covariance W_est must be 2x2")
|
|
333
|
+
|
|
334
|
+
# if np.any(self._sensor):
|
|
335
|
+
# self._landmarks = None*np.zeros(2, self._sensor.ekf_map.nlandmarks)
|
|
336
|
+
|
|
337
|
+
# # check types for passed objects
|
|
338
|
+
# if np.any(self._map) and not isinstance(self._map, 'LandmarkMap'):
|
|
339
|
+
# raise ValueError('expecting LandmarkMap object')
|
|
340
|
+
|
|
341
|
+
# if np.any(sensor) and not isinstance(sensor, 'Sensor'):
|
|
342
|
+
# raise ValueError('expecting Sensor object')
|
|
343
|
+
|
|
344
|
+
self.init()
|
|
345
|
+
|
|
346
|
+
self.xxdata = ([], [])
|
|
347
|
+
|
|
348
|
+
def __str__(self):
|
|
349
|
+
s = f"EKF object: {len(self._x_est)} states"
|
|
350
|
+
|
|
351
|
+
def indent(s, n=2):
|
|
352
|
+
spaces = " " * n
|
|
353
|
+
return s.replace("\n", "\n" + spaces)
|
|
354
|
+
|
|
355
|
+
estimating = []
|
|
356
|
+
if self._est_vehicle is not None:
|
|
357
|
+
estimating.append("vehicle pose")
|
|
358
|
+
if self._est_ekf_map is not None:
|
|
359
|
+
estimating.append("map")
|
|
360
|
+
if len(estimating) > 0:
|
|
361
|
+
s += ", estimating: " + ", ".join(estimating)
|
|
362
|
+
if self.robot is not None:
|
|
363
|
+
s += indent("\nrobot: " + str(self.robot))
|
|
364
|
+
if self.V_est is not None:
|
|
365
|
+
s += indent("\nV_est: " + base.array2str(self.V_est))
|
|
366
|
+
|
|
367
|
+
if self.sensor is not None:
|
|
368
|
+
s += indent("\nsensor: " + str(self.sensor))
|
|
369
|
+
if self.W_est is not None:
|
|
370
|
+
s += indent("\nW_est: " + base.array2str(self.W_est))
|
|
371
|
+
|
|
372
|
+
return s
|
|
373
|
+
|
|
374
|
+
def __repr__(self):
|
|
375
|
+
return str(self)
|
|
376
|
+
|
|
377
|
+
@property
|
|
378
|
+
def x_est(self):
|
|
379
|
+
"""
|
|
380
|
+
Get EKF state
|
|
381
|
+
|
|
382
|
+
:return: state vector
|
|
383
|
+
:rtype: ndarray(n)
|
|
384
|
+
|
|
385
|
+
Returns the value of the estimated state vector at the end of
|
|
386
|
+
simulation. The dimensions depend on the problem being solved.
|
|
387
|
+
"""
|
|
388
|
+
return self._x_est
|
|
389
|
+
|
|
390
|
+
@property
|
|
391
|
+
def P_est(self):
|
|
392
|
+
"""
|
|
393
|
+
Get EKF covariance
|
|
394
|
+
|
|
395
|
+
:return: covariance matrix
|
|
396
|
+
:rtype: ndarray(n,n)
|
|
397
|
+
|
|
398
|
+
Returns the value of the estimated covariance matrix at the end of
|
|
399
|
+
simulation. The dimensions depend on the problem being solved.
|
|
400
|
+
"""
|
|
401
|
+
return self._P_est
|
|
402
|
+
|
|
403
|
+
@property
|
|
404
|
+
def P0(self):
|
|
405
|
+
"""
|
|
406
|
+
Get initial EKF covariance
|
|
407
|
+
|
|
408
|
+
:return: covariance matrix
|
|
409
|
+
:rtype: ndarray(n,n)
|
|
410
|
+
|
|
411
|
+
Returns the value of the covariance matrix passed to the constructor.
|
|
412
|
+
"""
|
|
413
|
+
return self._P0
|
|
414
|
+
|
|
415
|
+
@property
|
|
416
|
+
def V_est(self):
|
|
417
|
+
"""
|
|
418
|
+
Get estimated odometry covariance
|
|
419
|
+
|
|
420
|
+
:return: odometry covariance
|
|
421
|
+
:rtype: ndarray(2,2)
|
|
422
|
+
|
|
423
|
+
Returns the value of the estimated odometry covariance matrix passed to
|
|
424
|
+
the constructor
|
|
425
|
+
"""
|
|
426
|
+
return self._V_est
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def W_est(self):
|
|
430
|
+
"""
|
|
431
|
+
Get estimated sensor covariance
|
|
432
|
+
|
|
433
|
+
:return: sensor covariance
|
|
434
|
+
:rtype: ndarray(2,2)
|
|
435
|
+
|
|
436
|
+
Returns the value of the estimated sensor covariance matrix passed to
|
|
437
|
+
the constructor
|
|
438
|
+
"""
|
|
439
|
+
return self._W_est
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def robot(self):
|
|
443
|
+
"""
|
|
444
|
+
Get robot object
|
|
445
|
+
|
|
446
|
+
:return: robot used in simulation
|
|
447
|
+
:rtype: :class:`VehicleBase` subclass
|
|
448
|
+
"""
|
|
449
|
+
return self._robot
|
|
450
|
+
|
|
451
|
+
@property
|
|
452
|
+
def sensor(self):
|
|
453
|
+
"""
|
|
454
|
+
Get sensor object
|
|
455
|
+
|
|
456
|
+
:return: sensor used in simulation
|
|
457
|
+
:rtype: :class:`SensorBase` subclass
|
|
458
|
+
"""
|
|
459
|
+
return self._sensor
|
|
460
|
+
|
|
461
|
+
@property
|
|
462
|
+
def map(self):
|
|
463
|
+
"""
|
|
464
|
+
Get map object
|
|
465
|
+
|
|
466
|
+
:return: map used in simulation
|
|
467
|
+
:rtype: :class:`LandmarkMap` subclass
|
|
468
|
+
"""
|
|
469
|
+
return self._map
|
|
470
|
+
|
|
471
|
+
@property
|
|
472
|
+
def verbose(self):
|
|
473
|
+
"""
|
|
474
|
+
Get verbosity state
|
|
475
|
+
|
|
476
|
+
:return: verbosity
|
|
477
|
+
:rtype: bool
|
|
478
|
+
"""
|
|
479
|
+
return self._verbose
|
|
480
|
+
|
|
481
|
+
@property
|
|
482
|
+
def history(self):
|
|
483
|
+
"""
|
|
484
|
+
Get EKF simulation history
|
|
485
|
+
|
|
486
|
+
:return: simulation history
|
|
487
|
+
:rtype: list of namedtuples
|
|
488
|
+
|
|
489
|
+
At each simulation timestep a namedtuple of is appended to the history
|
|
490
|
+
list. It contains, for that time step, estimated state and covariance,
|
|
491
|
+
and sensor observation.
|
|
492
|
+
|
|
493
|
+
:seealso: :meth:`get_t` :meth:`get_xyt` :meth:`get_map` :meth:`get_P`
|
|
494
|
+
:meth:`get_Pnorm`
|
|
495
|
+
"""
|
|
496
|
+
return self._history
|
|
497
|
+
|
|
498
|
+
@property
|
|
499
|
+
def workspace(self):
|
|
500
|
+
"""
|
|
501
|
+
Size of robot workspace
|
|
502
|
+
|
|
503
|
+
:return: workspace bounds [xmin, xmax, ymin, ymax]
|
|
504
|
+
:rtype: ndarray(4)
|
|
505
|
+
|
|
506
|
+
Returns the bounds of the workspace as specified by the constructor
|
|
507
|
+
option ``workspace``
|
|
508
|
+
"""
|
|
509
|
+
return self._workspace
|
|
510
|
+
|
|
511
|
+
@property
|
|
512
|
+
def landmarks(self):
|
|
513
|
+
"""
|
|
514
|
+
Get landmark information
|
|
515
|
+
|
|
516
|
+
:return: landmark information
|
|
517
|
+
:rtype: dict
|
|
518
|
+
|
|
519
|
+
The dictionary is indexed by the landmark id and gives a 3-tuple:
|
|
520
|
+
|
|
521
|
+
- order in which landmark was seen
|
|
522
|
+
- number of times seen
|
|
523
|
+
|
|
524
|
+
The order in which the landmark was first seen. The first observed
|
|
525
|
+
landmark has order 0 and so on.
|
|
526
|
+
|
|
527
|
+
:seealso: :meth:`landmark`
|
|
528
|
+
"""
|
|
529
|
+
return self._landmarks
|
|
530
|
+
|
|
531
|
+
def landmark(self, id):
|
|
532
|
+
"""
|
|
533
|
+
Landmark information
|
|
534
|
+
|
|
535
|
+
:param id: landmark index
|
|
536
|
+
:type id: int
|
|
537
|
+
:return: order in which it was first seen, number of times seen
|
|
538
|
+
:rtype: int, int
|
|
539
|
+
|
|
540
|
+
The first observed landmark has order 0 and so on.
|
|
541
|
+
|
|
542
|
+
:seealso: :meth:`landmarks` :meth:`landmark_index` :meth:`landmark_mindex`
|
|
543
|
+
"""
|
|
544
|
+
try:
|
|
545
|
+
l = self._landmarks[id]
|
|
546
|
+
return l[0], l[1]
|
|
547
|
+
except KeyError:
|
|
548
|
+
raise ValueError(f"unknown landmark {id}") from None
|
|
549
|
+
|
|
550
|
+
def landmark_index(self, id):
|
|
551
|
+
"""
|
|
552
|
+
Landmark index in complete state vector
|
|
553
|
+
|
|
554
|
+
:param id: landmark index
|
|
555
|
+
:type id: int
|
|
556
|
+
:return: index in the state vector
|
|
557
|
+
:rtype: int
|
|
558
|
+
|
|
559
|
+
The return value ``j`` is the index of the x-coordinate of the landmark
|
|
560
|
+
in the EKF state vector, and ``j+1`` is the index of the y-coordinate.
|
|
561
|
+
|
|
562
|
+
:seealso: :meth:`landmark`
|
|
563
|
+
"""
|
|
564
|
+
try:
|
|
565
|
+
jx = self._landmarks[id][0] * 2
|
|
566
|
+
if self._est_vehicle:
|
|
567
|
+
jx += 3
|
|
568
|
+
return jx
|
|
569
|
+
except KeyError:
|
|
570
|
+
raise ValueError(f"unknown landmark {id}") from None
|
|
571
|
+
|
|
572
|
+
def landmark_mindex(self, id):
|
|
573
|
+
"""
|
|
574
|
+
Landmark index in map state vector
|
|
575
|
+
|
|
576
|
+
:param id: landmark index
|
|
577
|
+
:type id: int
|
|
578
|
+
:return: index in the state vector
|
|
579
|
+
:rtype: int
|
|
580
|
+
|
|
581
|
+
The return value ``j`` is the index of the x-coordinate of the landmark
|
|
582
|
+
in the map vector, and ``j+1`` is the index of the y-coordinate.
|
|
583
|
+
|
|
584
|
+
:seealso: :meth:`landmark`
|
|
585
|
+
"""
|
|
586
|
+
try:
|
|
587
|
+
return self._landmarks[id][0] * 2
|
|
588
|
+
except KeyError:
|
|
589
|
+
raise ValueError(f"unknown landmark {id}") from None
|
|
590
|
+
|
|
591
|
+
def landmark_x(self, id):
|
|
592
|
+
"""
|
|
593
|
+
Landmark position
|
|
594
|
+
|
|
595
|
+
:param id: landmark index
|
|
596
|
+
:type id: int
|
|
597
|
+
:return: landmark position :math:`(x,y)`
|
|
598
|
+
:rtype: ndarray(2)
|
|
599
|
+
|
|
600
|
+
Returns the landmark position from the current state vector.
|
|
601
|
+
"""
|
|
602
|
+
jx = self.landmark_index(id)
|
|
603
|
+
return self._x_est[jx : jx + 2]
|
|
604
|
+
|
|
605
|
+
def init(self):
|
|
606
|
+
# EKF.init Reset the filter
|
|
607
|
+
#
|
|
608
|
+
# E.init() resets the filter state and clears landmarks and history.
|
|
609
|
+
self.robot.init()
|
|
610
|
+
if self.sensor is not None:
|
|
611
|
+
self.sensor.init()
|
|
612
|
+
|
|
613
|
+
# clear the history
|
|
614
|
+
self._history = []
|
|
615
|
+
|
|
616
|
+
if self._V_est is None:
|
|
617
|
+
# perfect vehicle case
|
|
618
|
+
self._estVehicle = False
|
|
619
|
+
self._x_est = np.empty((0,))
|
|
620
|
+
self._P_est = np.empty((0, 0))
|
|
621
|
+
else:
|
|
622
|
+
# noisy odometry case
|
|
623
|
+
self._x_est = self._x0
|
|
624
|
+
self._P_est = self._P0
|
|
625
|
+
self._estVehicle = True
|
|
626
|
+
|
|
627
|
+
if self.sensor is not None:
|
|
628
|
+
# landmark dictionary maps lm_id to list[index, nseen]
|
|
629
|
+
self._landmarks = {}
|
|
630
|
+
|
|
631
|
+
# np.full((2, len(self.sensor.map)), -1, dtype=int)
|
|
632
|
+
|
|
633
|
+
def run(self, T, animate=False):
|
|
634
|
+
"""
|
|
635
|
+
Run the EKF simulation
|
|
636
|
+
|
|
637
|
+
:param T: maximum simulation time in seconds
|
|
638
|
+
:type T: float
|
|
639
|
+
:param animate: animate motion of vehicle, defaults to False
|
|
640
|
+
:type animate: bool, optional
|
|
641
|
+
|
|
642
|
+
Simulates the motion of a vehicle (under the control of a driving agent)
|
|
643
|
+
and the EKF estimator. The steps are:
|
|
644
|
+
|
|
645
|
+
- initialize the filter, vehicle and vehicle driver agent, sensor
|
|
646
|
+
- for each time step:
|
|
647
|
+
|
|
648
|
+
- step the vehicle and its driver agent, obtain odometry
|
|
649
|
+
- take a sensor reading
|
|
650
|
+
- execute the EKF
|
|
651
|
+
- save information as a namedtuple to the history list for later display
|
|
652
|
+
|
|
653
|
+
:seealso: :meth:`history` :meth:`landmark` :meth:`landmarks`
|
|
654
|
+
:meth:`get_xyt` :meth:`get_t` :meth:`get_map` :meth:`get_P` :meth:`get_Pnorm`
|
|
655
|
+
:meth:`plot_xy` :meth:`plot_ellipse` :meth:`plot_error` :meth:`plot_map`
|
|
656
|
+
:meth:`run_animation`
|
|
657
|
+
"""
|
|
658
|
+
self.init()
|
|
659
|
+
if animate:
|
|
660
|
+
if self.sensor is not None:
|
|
661
|
+
self.sensor.map.plot()
|
|
662
|
+
|
|
663
|
+
plt.xlabel("X")
|
|
664
|
+
plt.ylabel("Y")
|
|
665
|
+
|
|
666
|
+
for k in range(round(T / self.robot.dt)):
|
|
667
|
+
if animate:
|
|
668
|
+
# self.robot.plot()
|
|
669
|
+
self.robot._animation.update(self.robot.x)
|
|
670
|
+
self.step()
|
|
671
|
+
|
|
672
|
+
def run_animation(self, T=10, x0=None, control=None, format=None, file=None):
|
|
673
|
+
r"""
|
|
674
|
+
Run the EKF simulation
|
|
675
|
+
|
|
676
|
+
:param T: maximum simulation time in seconds
|
|
677
|
+
:type T: float
|
|
678
|
+
:param format: Output format
|
|
679
|
+
:type format: str, optional
|
|
680
|
+
:param file: File name
|
|
681
|
+
:type file: str, optional
|
|
682
|
+
:return: Matplotlib animation object
|
|
683
|
+
:rtype: :meth:`matplotlib.animation.FuncAnimation`
|
|
684
|
+
|
|
685
|
+
Simulates the motion of a vehicle (under the control of a driving agent)
|
|
686
|
+
and the EKF estimator for ``T`` seconds and returns an animation
|
|
687
|
+
in various formats::
|
|
688
|
+
|
|
689
|
+
``format`` ``file`` description
|
|
690
|
+
============ ========= ============================
|
|
691
|
+
``"html"`` str, None return HTML5 video
|
|
692
|
+
``"jshtml"`` str, None return JS+HTML video
|
|
693
|
+
``"gif"`` str return animated GIF
|
|
694
|
+
``"mp4"`` str return MP4/H264 video
|
|
695
|
+
``None`` return a ``FuncAnimation`` object
|
|
696
|
+
|
|
697
|
+
If ``file`` can be ``None`` then return the video as a string, otherwise it
|
|
698
|
+
must be a filename.
|
|
699
|
+
|
|
700
|
+
The simulation steps are:
|
|
701
|
+
|
|
702
|
+
- initialize the filter, vehicle and vehicle driver agent, sensor
|
|
703
|
+
- for each time step:
|
|
704
|
+
|
|
705
|
+
- step the vehicle and its driver agent, obtain odometry
|
|
706
|
+
- take a sensor reading
|
|
707
|
+
- execute the EKF
|
|
708
|
+
- save information as a namedtuple to the history list for later display
|
|
709
|
+
|
|
710
|
+
:seealso: :meth:`history` :meth:`landmark` :meth:`landmarks`
|
|
711
|
+
:meth:`get_xyt` :meth:`get_t` :meth:`get_map` :meth:`get_P` :meth:`get_Pnorm`
|
|
712
|
+
:meth:`plot_xy` :meth:`plot_ellipse` :meth:`plot_error` :meth:`plot_map`
|
|
713
|
+
:meth:`run_animation`
|
|
714
|
+
"""
|
|
715
|
+
|
|
716
|
+
fig, ax = plt.subplots()
|
|
717
|
+
|
|
718
|
+
def init():
|
|
719
|
+
self.init()
|
|
720
|
+
if self.sensor is not None:
|
|
721
|
+
self.sensor.map.plot()
|
|
722
|
+
ax.set_xlabel("X")
|
|
723
|
+
ax.set_ylabel("Y")
|
|
724
|
+
|
|
725
|
+
def animate(i):
|
|
726
|
+
self.robot._animation.update(self.robot.x)
|
|
727
|
+
self.step(pause=False)
|
|
728
|
+
|
|
729
|
+
nframes = round(T / self.robot._dt)
|
|
730
|
+
anim = animation.FuncAnimation(
|
|
731
|
+
fig=fig,
|
|
732
|
+
func=animate,
|
|
733
|
+
init_func=init,
|
|
734
|
+
frames=nframes,
|
|
735
|
+
interval=self.robot.dt * 1000,
|
|
736
|
+
blit=False,
|
|
737
|
+
repeat=False,
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
ret = None
|
|
741
|
+
if format == "html":
|
|
742
|
+
ret = anim.to_html5_video() # convert to embeddable HTML5 animation
|
|
743
|
+
elif format == "jshtml":
|
|
744
|
+
ret = anim.to_jshtml() # convert to embeddable Javascript/HTML animation
|
|
745
|
+
elif format == "gif":
|
|
746
|
+
anim.save(
|
|
747
|
+
file, writer=animation.PillowWriter(fps=1 / self.robot.dt)
|
|
748
|
+
) # convert to GIF
|
|
749
|
+
ret = None
|
|
750
|
+
elif format == "mp4":
|
|
751
|
+
anim.save(
|
|
752
|
+
file, writer=animation.FFMpegWriter(fps=1 / self.robot.dt)
|
|
753
|
+
) # convert to mp4/H264
|
|
754
|
+
ret = None
|
|
755
|
+
elif format == None:
|
|
756
|
+
# return the anim object
|
|
757
|
+
return anim
|
|
758
|
+
else:
|
|
759
|
+
raise ValueError("unknown format")
|
|
760
|
+
|
|
761
|
+
if ret is not None and file is not None:
|
|
762
|
+
with open(file, "w") as f:
|
|
763
|
+
f.write(ret)
|
|
764
|
+
ret = None
|
|
765
|
+
plt.close(fig)
|
|
766
|
+
return ret
|
|
767
|
+
|
|
768
|
+
def step(self, pause=None):
|
|
769
|
+
"""
|
|
770
|
+
Execute one timestep of the simulation
|
|
771
|
+
"""
|
|
772
|
+
|
|
773
|
+
# move the robot
|
|
774
|
+
odo = self.robot.step(pause=pause)
|
|
775
|
+
|
|
776
|
+
# =================================================================
|
|
777
|
+
# P R E D I C T I O N
|
|
778
|
+
# =================================================================
|
|
779
|
+
if self._est_vehicle:
|
|
780
|
+
# split the state vector and covariance into chunks for
|
|
781
|
+
# vehicle and map
|
|
782
|
+
xv_est = self._x_est[:3]
|
|
783
|
+
xm_est = self._x_est[3:]
|
|
784
|
+
Pvv_est = self._P_est[:3, :3]
|
|
785
|
+
Pmm_est = self._P_est[3:, 3:]
|
|
786
|
+
Pvm_est = self._P_est[:3, 3:]
|
|
787
|
+
else:
|
|
788
|
+
xm_est = self._x_est
|
|
789
|
+
Pmm_est = self._P_est
|
|
790
|
+
|
|
791
|
+
if self._est_vehicle:
|
|
792
|
+
# evaluate the state update function and the Jacobians
|
|
793
|
+
# if vehicle has uncertainty, predict its covariance
|
|
794
|
+
xv_pred = self.robot.f(xv_est, odo)
|
|
795
|
+
|
|
796
|
+
Fx = self.robot.Fx(xv_est, odo)
|
|
797
|
+
Fv = self.robot.Fv(xv_est, odo)
|
|
798
|
+
Pvv_pred = Fx @ Pvv_est @ Fx.T + Fv @ self.V_est @ Fv.T
|
|
799
|
+
else:
|
|
800
|
+
# otherwise we just take the true robot state
|
|
801
|
+
xv_pred = self._robot.x
|
|
802
|
+
|
|
803
|
+
if self._est_ekf_map:
|
|
804
|
+
if self._est_vehicle:
|
|
805
|
+
# SLAM case, compute the correlations
|
|
806
|
+
Pvm_pred = Fx @ Pvm_est
|
|
807
|
+
|
|
808
|
+
Pmm_pred = Pmm_est
|
|
809
|
+
xm_pred = xm_est
|
|
810
|
+
|
|
811
|
+
# put the chunks back together again
|
|
812
|
+
if self._est_vehicle and not self._est_ekf_map:
|
|
813
|
+
# vehicle only
|
|
814
|
+
x_pred = xv_pred
|
|
815
|
+
P_pred = Pvv_pred
|
|
816
|
+
elif not self._est_vehicle and self._est_ekf_map:
|
|
817
|
+
# map only
|
|
818
|
+
x_pred = xm_pred
|
|
819
|
+
P_pred = Pmm_pred
|
|
820
|
+
elif self._est_vehicle and self._est_ekf_map:
|
|
821
|
+
# vehicle and map
|
|
822
|
+
x_pred = np.r_[xv_pred, xm_pred]
|
|
823
|
+
# fmt: off
|
|
824
|
+
P_pred = np.block([
|
|
825
|
+
[Pvv_pred, Pvm_pred],
|
|
826
|
+
[Pvm_pred.T, Pmm_pred]
|
|
827
|
+
])
|
|
828
|
+
# fmt: on
|
|
829
|
+
|
|
830
|
+
# at this point we have:
|
|
831
|
+
# xv_pred the state of the vehicle to use to
|
|
832
|
+
# predict observations
|
|
833
|
+
# xm_pred the state of the map
|
|
834
|
+
# x_pred the full predicted state vector
|
|
835
|
+
# P_pred the full predicted covariance matrix
|
|
836
|
+
|
|
837
|
+
# initialize the variables that might be computed during
|
|
838
|
+
# the update phase
|
|
839
|
+
|
|
840
|
+
doUpdatePhase = False
|
|
841
|
+
|
|
842
|
+
# disp('x_pred:') x_pred'
|
|
843
|
+
|
|
844
|
+
# =================================================================
|
|
845
|
+
# P R O C E S S O B S E R V A T I O N S
|
|
846
|
+
# =================================================================
|
|
847
|
+
|
|
848
|
+
if self.sensor is not None:
|
|
849
|
+
# read the sensor
|
|
850
|
+
z, lm_id = self.sensor.reading()
|
|
851
|
+
sensorReading = z is not None
|
|
852
|
+
else:
|
|
853
|
+
lm_id = None # keep history saving happy
|
|
854
|
+
z = None
|
|
855
|
+
sensorReading = False
|
|
856
|
+
|
|
857
|
+
if sensorReading:
|
|
858
|
+
# here for MBL, MM, SLAM
|
|
859
|
+
|
|
860
|
+
# compute the innovation
|
|
861
|
+
z_pred = self.sensor.h(xv_pred, lm_id)
|
|
862
|
+
innov = np.array([z[0] - z_pred[0], base.wrap_mpi_pi(z[1] - z_pred[1])])
|
|
863
|
+
|
|
864
|
+
if self._est_ekf_map:
|
|
865
|
+
# the ekf_map is estimated MM or SLAM case
|
|
866
|
+
if self._isseenbefore(lm_id):
|
|
867
|
+
# landmark is previously seen
|
|
868
|
+
|
|
869
|
+
# get previous estimate of its state
|
|
870
|
+
jx = self.landmark_mindex(lm_id)
|
|
871
|
+
xf = xm_pred[jx : jx + 2]
|
|
872
|
+
|
|
873
|
+
# compute Jacobian for this particular landmark
|
|
874
|
+
# xf = self.sensor.g(xv_pred, z) # HACK
|
|
875
|
+
Hx_k = self.sensor.Hp(xv_pred, xf)
|
|
876
|
+
|
|
877
|
+
z_pred = self.sensor.h(xv_pred, xf)
|
|
878
|
+
innov = np.array(
|
|
879
|
+
[z[0] - z_pred[0], base.wrap_mpi_pi(z[1] - z_pred[1])]
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
# create the Jacobian for all landmarks
|
|
883
|
+
Hx = np.zeros((2, len(xm_pred)))
|
|
884
|
+
Hx[:, jx : jx + 2] = Hx_k
|
|
885
|
+
|
|
886
|
+
Hw = self.sensor.Hw(xv_pred, xf)
|
|
887
|
+
|
|
888
|
+
if self._est_vehicle:
|
|
889
|
+
# concatenate Hx for for vehicle and ekf_map
|
|
890
|
+
Hxv = self.sensor.Hx(xv_pred, xf)
|
|
891
|
+
Hx = np.block([Hxv, Hx])
|
|
892
|
+
|
|
893
|
+
self._landmark_increment(lm_id) # update the count
|
|
894
|
+
if self._verbose:
|
|
895
|
+
print(
|
|
896
|
+
f"landmark {lm_id} seen"
|
|
897
|
+
f" {self._landmark_count(lm_id)} times,"
|
|
898
|
+
f" state_idx={self.landmark_index(lm_id)}"
|
|
899
|
+
)
|
|
900
|
+
doUpdatePhase = True
|
|
901
|
+
|
|
902
|
+
else:
|
|
903
|
+
# new landmark, seen for the first time
|
|
904
|
+
|
|
905
|
+
# extend the state vector and covariance
|
|
906
|
+
x_pred, P_pred = self._extend_map(
|
|
907
|
+
P_pred, xv_pred, xm_pred, z, lm_id
|
|
908
|
+
)
|
|
909
|
+
# if lm_id == 17:
|
|
910
|
+
# print(P_pred)
|
|
911
|
+
# # print(x_pred[-2:], self._sensor._map.landmark(17), base.norm(x_pred[-2:] - self._sensor._map.landmark(17)))
|
|
912
|
+
|
|
913
|
+
self._landmark_add(lm_id)
|
|
914
|
+
if self._verbose:
|
|
915
|
+
print(
|
|
916
|
+
f"landmark {lm_id} seen for first time,"
|
|
917
|
+
f" state_idx={self.landmark_index(lm_id)}"
|
|
918
|
+
)
|
|
919
|
+
doUpdatePhase = False
|
|
920
|
+
|
|
921
|
+
else:
|
|
922
|
+
# LBL
|
|
923
|
+
Hx = self.sensor.Hx(xv_pred, lm_id)
|
|
924
|
+
Hw = self.sensor.Hw(xv_pred, lm_id)
|
|
925
|
+
doUpdatePhase = True
|
|
926
|
+
else:
|
|
927
|
+
innov = None
|
|
928
|
+
|
|
929
|
+
# doUpdatePhase flag indicates whether or not to do
|
|
930
|
+
# the update phase of the filter
|
|
931
|
+
#
|
|
932
|
+
# DR always false
|
|
933
|
+
# map-based localization if sensor reading
|
|
934
|
+
# map creation if sensor reading & not first
|
|
935
|
+
# sighting
|
|
936
|
+
# SLAM if sighting of a previously
|
|
937
|
+
# seen landmark
|
|
938
|
+
|
|
939
|
+
if doUpdatePhase:
|
|
940
|
+
# disp('do update\n')
|
|
941
|
+
# # we have innovation, update state and covariance
|
|
942
|
+
# compute x_est and P_est
|
|
943
|
+
|
|
944
|
+
# compute innovation covariance
|
|
945
|
+
S = Hx @ P_pred @ Hx.T + Hw @ self._W_est @ Hw.T
|
|
946
|
+
|
|
947
|
+
# compute the Kalman gain
|
|
948
|
+
K = P_pred @ Hx.T @ np.linalg.inv(S)
|
|
949
|
+
|
|
950
|
+
# update the state vector
|
|
951
|
+
x_est = x_pred + K @ innov
|
|
952
|
+
|
|
953
|
+
if self._est_vehicle:
|
|
954
|
+
# wrap heading state for a vehicle
|
|
955
|
+
x_est[2] = base.wrap_mpi_pi(x_est[2])
|
|
956
|
+
|
|
957
|
+
# update the covariance
|
|
958
|
+
if self._joseph:
|
|
959
|
+
# we use the Joseph form
|
|
960
|
+
I = np.eye(P_pred.shape[0])
|
|
961
|
+
P_est = (I - K @ Hx) @ P_pred @ (I - K @ Hx).T + K @ self._W_est @ K.T
|
|
962
|
+
else:
|
|
963
|
+
P_est = P_pred - K @ S @ K.T
|
|
964
|
+
# enforce P to be symmetric
|
|
965
|
+
P_est = 0.5 * (P_est + P_est.T)
|
|
966
|
+
else:
|
|
967
|
+
# no update phase, estimate is same as prediction
|
|
968
|
+
x_est = x_pred
|
|
969
|
+
P_est = P_pred
|
|
970
|
+
S = None
|
|
971
|
+
K = None
|
|
972
|
+
|
|
973
|
+
self._x_est = x_est
|
|
974
|
+
self._P_est = P_est
|
|
975
|
+
|
|
976
|
+
if self._keep_history:
|
|
977
|
+
hist = self._htuple(
|
|
978
|
+
self.robot._t,
|
|
979
|
+
x_est.copy(),
|
|
980
|
+
odo.copy(),
|
|
981
|
+
P_est.copy(),
|
|
982
|
+
innov.copy() if innov is not None else None,
|
|
983
|
+
S.copy() if S is not None else None,
|
|
984
|
+
K.copy() if K is not None else None,
|
|
985
|
+
lm_id if lm_id is not None else -1,
|
|
986
|
+
z.copy() if z is not None else None,
|
|
987
|
+
)
|
|
988
|
+
self._history.append(hist)
|
|
989
|
+
|
|
990
|
+
## landmark management
|
|
991
|
+
|
|
992
|
+
def _isseenbefore(self, lm_id):
|
|
993
|
+
|
|
994
|
+
# _landmarks[0, id] is the order in which seen
|
|
995
|
+
# _landmarks[1, id] is the occurence count
|
|
996
|
+
|
|
997
|
+
return lm_id in self._landmarks
|
|
998
|
+
|
|
999
|
+
def _landmark_increment(self, lm_id):
|
|
1000
|
+
self._landmarks[lm_id][1] += 1 # update the count
|
|
1001
|
+
|
|
1002
|
+
def _landmark_count(self, lm_id):
|
|
1003
|
+
return self._landmarks[lm_id][1]
|
|
1004
|
+
|
|
1005
|
+
def _landmark_add(self, lm_id):
|
|
1006
|
+
self._landmarks[lm_id] = [len(self._landmarks), 1]
|
|
1007
|
+
|
|
1008
|
+
def _extend_map(self, P, xv, xm, z, lm_id):
|
|
1009
|
+
# this is a new landmark, we haven't seen it before
|
|
1010
|
+
# estimate position of landmark in the world based on
|
|
1011
|
+
# noisy sensor reading and current vehicle pose
|
|
1012
|
+
|
|
1013
|
+
# M = None
|
|
1014
|
+
|
|
1015
|
+
# estimate its position based on observation and vehicle state
|
|
1016
|
+
xf = self.sensor.g(xv, z)
|
|
1017
|
+
|
|
1018
|
+
# append this estimate to the state vector
|
|
1019
|
+
if self._est_vehicle:
|
|
1020
|
+
x_ext = np.r_[xv, xm, xf]
|
|
1021
|
+
else:
|
|
1022
|
+
x_ext = np.r_[xm, xf]
|
|
1023
|
+
|
|
1024
|
+
# get the Jacobian for the new landmark
|
|
1025
|
+
Gz = self.sensor.Gz(xv, z)
|
|
1026
|
+
|
|
1027
|
+
# extend the covariance matrix
|
|
1028
|
+
n = len(self._x_est)
|
|
1029
|
+
if self._est_vehicle:
|
|
1030
|
+
# estimating vehicle state
|
|
1031
|
+
Gx = self.sensor.Gx(xv, z)
|
|
1032
|
+
# fmt: off
|
|
1033
|
+
Yz = np.block([
|
|
1034
|
+
[np.eye(n), np.zeros((n, 2)) ],
|
|
1035
|
+
[Gx, np.zeros((2, n-3)), Gz]
|
|
1036
|
+
])
|
|
1037
|
+
# fmt: on
|
|
1038
|
+
else:
|
|
1039
|
+
# estimating landmarks only
|
|
1040
|
+
# P_ext = block_diag(P, Gz @ self._W_est @ Gz.T)
|
|
1041
|
+
# fmt: off
|
|
1042
|
+
Yz = np.block([
|
|
1043
|
+
[np.eye(n), np.zeros((n, 2)) ],
|
|
1044
|
+
[np.zeros((2, n)), Gz]
|
|
1045
|
+
])
|
|
1046
|
+
# fmt: on
|
|
1047
|
+
P_ext = Yz @ block_diag(P, self._W_est) @ Yz.T
|
|
1048
|
+
|
|
1049
|
+
return x_ext, P_ext
|
|
1050
|
+
|
|
1051
|
+
def get_t(self):
|
|
1052
|
+
"""
|
|
1053
|
+
Get time from simulation
|
|
1054
|
+
|
|
1055
|
+
:return: simulation time vector
|
|
1056
|
+
:rtype: ndarray(n)
|
|
1057
|
+
|
|
1058
|
+
Return simulation time vector, starts at zero. The timestep is an
|
|
1059
|
+
attribute of the ``robot`` object.
|
|
1060
|
+
|
|
1061
|
+
:seealso: :meth:`run` :meth:`history`
|
|
1062
|
+
"""
|
|
1063
|
+
return np.array([h.t for h in self._history])
|
|
1064
|
+
|
|
1065
|
+
def get_xyt(self):
|
|
1066
|
+
r"""
|
|
1067
|
+
Get estimated vehicle trajectory
|
|
1068
|
+
|
|
1069
|
+
:return: vehicle trajectory where each row is configuration :math:`(x, y, \theta)`
|
|
1070
|
+
:rtype: ndarray(n,3)
|
|
1071
|
+
|
|
1072
|
+
:seealso: :meth:`plot_xy` :meth:`run` :meth:`history`
|
|
1073
|
+
"""
|
|
1074
|
+
if self._est_vehicle:
|
|
1075
|
+
xyt = np.array([h.xest[:3] for h in self._history])
|
|
1076
|
+
else:
|
|
1077
|
+
xyt = None
|
|
1078
|
+
return xyt
|
|
1079
|
+
|
|
1080
|
+
def plot_xy(self, *args, block=None, **kwargs):
|
|
1081
|
+
"""
|
|
1082
|
+
Plot estimated vehicle position
|
|
1083
|
+
|
|
1084
|
+
:param args: position arguments passed to :meth:`~matplotlib.axes.Axes.plot`
|
|
1085
|
+
:param kwargs: keywords arguments passed to :meth:`~matplotlib.axes.Axes.plot`
|
|
1086
|
+
:param block: hold plot until figure is closed, defaults to None
|
|
1087
|
+
:type block: bool, optional
|
|
1088
|
+
|
|
1089
|
+
Plot the estimated vehicle path in the xy-plane.
|
|
1090
|
+
|
|
1091
|
+
:seealso: :meth:`get_xyt` :meth:`plot_error` :meth:`plot_ellipse` :meth:`plot_P`
|
|
1092
|
+
:meth:`run` :meth:`history`
|
|
1093
|
+
"""
|
|
1094
|
+
if args is None and "color" not in kwargs:
|
|
1095
|
+
kwargs["color"] = "r"
|
|
1096
|
+
xyt = self.get_xyt()
|
|
1097
|
+
plt.plot(xyt[:, 0], xyt[:, 1], *args, **kwargs)
|
|
1098
|
+
if block is not None:
|
|
1099
|
+
plt.show(block=block)
|
|
1100
|
+
|
|
1101
|
+
def plot_ellipse(self, confidence=0.95, N=10, block=None, **kwargs):
|
|
1102
|
+
"""
|
|
1103
|
+
Plot uncertainty ellipses
|
|
1104
|
+
|
|
1105
|
+
:param confidence: ellipse confidence interval, defaults to 0.95
|
|
1106
|
+
:type confidence: float, optional
|
|
1107
|
+
:param N: number of ellipses to plot, defaults to 10
|
|
1108
|
+
:type N: int, optional
|
|
1109
|
+
:param block: hold plot until figure is closed, defaults to None
|
|
1110
|
+
:type block: bool, optional
|
|
1111
|
+
:param kwargs: arguments passed to :meth:`spatialmath.base.graphics.plot_ellipse`
|
|
1112
|
+
|
|
1113
|
+
Plot ``N`` uncertainty ellipses spaced evenly along the trajectory.
|
|
1114
|
+
|
|
1115
|
+
:seealso: :meth:`get_P` :meth:`run` :meth:`history`
|
|
1116
|
+
"""
|
|
1117
|
+
nhist = len(self._history)
|
|
1118
|
+
|
|
1119
|
+
if "label" in kwargs:
|
|
1120
|
+
label = kwargs["label"]
|
|
1121
|
+
del kwargs["label"]
|
|
1122
|
+
else:
|
|
1123
|
+
label = f"{confidence * 100:.3g}% confidence"
|
|
1124
|
+
|
|
1125
|
+
for k in np.linspace(0, nhist - 1, N):
|
|
1126
|
+
k = round(k)
|
|
1127
|
+
h = self._history[k]
|
|
1128
|
+
if k == 0:
|
|
1129
|
+
base.plot_ellipse(
|
|
1130
|
+
h.P[:2, :2],
|
|
1131
|
+
centre=h.xest[:2],
|
|
1132
|
+
confidence=confidence,
|
|
1133
|
+
label=label,
|
|
1134
|
+
inverted=True,
|
|
1135
|
+
**kwargs,
|
|
1136
|
+
)
|
|
1137
|
+
else:
|
|
1138
|
+
base.plot_ellipse(
|
|
1139
|
+
h.P[:2, :2],
|
|
1140
|
+
centre=h.xest[:2],
|
|
1141
|
+
confidence=confidence,
|
|
1142
|
+
inverted=True,
|
|
1143
|
+
**kwargs,
|
|
1144
|
+
)
|
|
1145
|
+
if block is not None:
|
|
1146
|
+
plt.show(block=block)
|
|
1147
|
+
|
|
1148
|
+
def plot_error(self, bgcolor="r", confidence=0.95, ax=None, block=None, **kwargs):
|
|
1149
|
+
r"""
|
|
1150
|
+
Plot error with uncertainty bounds
|
|
1151
|
+
|
|
1152
|
+
:param bgcolor: background color, defaults to 'r'
|
|
1153
|
+
:type bgcolor: str, optional
|
|
1154
|
+
:param confidence: confidence interval, defaults to 0.95
|
|
1155
|
+
:type confidence: float, optional
|
|
1156
|
+
:param block: hold plot until figure is closed, defaults to None
|
|
1157
|
+
:type block: bool, optional
|
|
1158
|
+
|
|
1159
|
+
Plot the error between actual and estimated vehicle
|
|
1160
|
+
path :math:`(x, y, \theta)`` versus time as three stacked plots.
|
|
1161
|
+
Heading error is wrapped into the range :math:`[-\pi,\pi)`
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
Behind each line draw a shaded polygon ``bgcolor`` showing the specified
|
|
1165
|
+
``confidence`` bounds based on the covariance at each time step.
|
|
1166
|
+
Ideally the lines should be within the shaded polygon ``confidence``
|
|
1167
|
+
of the time.
|
|
1168
|
+
|
|
1169
|
+
.. note:: Observations will decrease the uncertainty while periods of dead-reckoning increase it.
|
|
1170
|
+
|
|
1171
|
+
:seealso: :meth:`get_P` :meth:`run` :meth:`history`
|
|
1172
|
+
"""
|
|
1173
|
+
error = []
|
|
1174
|
+
bounds = []
|
|
1175
|
+
ppf = chi2.ppf(confidence, df=2)
|
|
1176
|
+
|
|
1177
|
+
x_gt = self.robot.x_hist
|
|
1178
|
+
for k in range(len(self.history)):
|
|
1179
|
+
hk = self.history[k]
|
|
1180
|
+
# error is true - estimated
|
|
1181
|
+
e = x_gt[k, :] - hk.xest
|
|
1182
|
+
e[2] = base.wrap_mpi_pi(e[2])
|
|
1183
|
+
error.append(e)
|
|
1184
|
+
|
|
1185
|
+
P = np.diag(hk.P)
|
|
1186
|
+
bounds.append(np.sqrt(ppf * P[:3]))
|
|
1187
|
+
|
|
1188
|
+
error = np.array(error)
|
|
1189
|
+
bounds = np.array(bounds)
|
|
1190
|
+
t = self.get_t()
|
|
1191
|
+
|
|
1192
|
+
if ax is None:
|
|
1193
|
+
fig, axes = plt.subplots(3)
|
|
1194
|
+
else:
|
|
1195
|
+
axes = ax[:3]
|
|
1196
|
+
labels = ["x", "y", r"$\theta$"]
|
|
1197
|
+
|
|
1198
|
+
for k, ax in enumerate(axes):
|
|
1199
|
+
if confidence is not None:
|
|
1200
|
+
edge = np.array(
|
|
1201
|
+
[
|
|
1202
|
+
np.r_[t, t[::-1]],
|
|
1203
|
+
np.r_[bounds[:, k], -bounds[::-1, k]],
|
|
1204
|
+
]
|
|
1205
|
+
)
|
|
1206
|
+
polygon = plt.Polygon(
|
|
1207
|
+
edge.T, closed=True, facecolor="r", edgecolor="none", alpha=0.3
|
|
1208
|
+
)
|
|
1209
|
+
ax.add_patch(polygon)
|
|
1210
|
+
ax.plot(error[:, k], **kwargs)
|
|
1211
|
+
ax.grid(True)
|
|
1212
|
+
ax.set_ylabel(labels[k] + " error")
|
|
1213
|
+
ax.set_xlim(0, t[-1])
|
|
1214
|
+
|
|
1215
|
+
if block is not None:
|
|
1216
|
+
plt.show(block=block)
|
|
1217
|
+
|
|
1218
|
+
# subplot(opt.nplots*100+12)
|
|
1219
|
+
# if opt.confidence
|
|
1220
|
+
# edge = [pxy(:,2); -pxy(end:-1:1,2)];
|
|
1221
|
+
# h = patch(t, edge, opt.color);
|
|
1222
|
+
# set(h, 'EdgeColor', 'none', 'FaceAlpha', 0.3);
|
|
1223
|
+
# end
|
|
1224
|
+
# hold on
|
|
1225
|
+
# plot(err(:,2), args{:});
|
|
1226
|
+
# hold off
|
|
1227
|
+
# grid
|
|
1228
|
+
# ylabel('y error')
|
|
1229
|
+
|
|
1230
|
+
# subplot(opt.nplots*100+13)
|
|
1231
|
+
# if opt.confidence
|
|
1232
|
+
# edge = [pxy(:,3); -pxy(end:-1:1,3)];
|
|
1233
|
+
# h = patch(t, edge, opt.color);
|
|
1234
|
+
# set(h, 'EdgeColor', 'none', 'FaceAlpha', 0.3);
|
|
1235
|
+
# end
|
|
1236
|
+
# hold on
|
|
1237
|
+
# plot(err(:,3), args{:});
|
|
1238
|
+
# hold off
|
|
1239
|
+
# grid
|
|
1240
|
+
# xlabel('Time step')
|
|
1241
|
+
# ylabel('\theta error')
|
|
1242
|
+
|
|
1243
|
+
def get_map(self):
|
|
1244
|
+
"""
|
|
1245
|
+
Get estimated map
|
|
1246
|
+
|
|
1247
|
+
:return: landmark coordinates :math:`(x, y)`
|
|
1248
|
+
:rtype: ndarray(n,2)
|
|
1249
|
+
|
|
1250
|
+
Landmarks are returned in the order they were first observed.
|
|
1251
|
+
|
|
1252
|
+
:seealso: :meth:`landmarks` :meth:`run` :meth:`history`
|
|
1253
|
+
|
|
1254
|
+
"""
|
|
1255
|
+
xy = []
|
|
1256
|
+
for lm_id, (jx, n) in self._landmarks.items():
|
|
1257
|
+
# jx is an index into the *landmark* part of the state
|
|
1258
|
+
# vector, we need to offset it to account for the vehicle
|
|
1259
|
+
# state if we are estimating vehicle as well
|
|
1260
|
+
if self._est_vehicle:
|
|
1261
|
+
jx += 3
|
|
1262
|
+
xf = self._x_est[jx : jx + 2]
|
|
1263
|
+
xy.append(xf)
|
|
1264
|
+
return np.array(xy)
|
|
1265
|
+
|
|
1266
|
+
def plot_map(self, marker=None, ellipse=None, confidence=0.95, block=None):
|
|
1267
|
+
"""
|
|
1268
|
+
Plot estimated landmarks
|
|
1269
|
+
|
|
1270
|
+
:param marker: plot marker for landmark, arguments passed to :meth:`~matplotlib.axes.Axes.plot`, defaults to "r+"
|
|
1271
|
+
:type marker: dict, optional
|
|
1272
|
+
:param ellipse: arguments passed to :meth:`~spatialmath.base.graphics.plot_ellipse`, defaults to None
|
|
1273
|
+
:type ellipse: dict, optional
|
|
1274
|
+
:param confidence: ellipse confidence interval, defaults to 0.95
|
|
1275
|
+
:type confidence: float, optional
|
|
1276
|
+
:param block: hold plot until figure is closed, defaults to None
|
|
1277
|
+
:type block: bool, optional
|
|
1278
|
+
|
|
1279
|
+
Plot a marker and covariance ellipses for each estimated landmark.
|
|
1280
|
+
|
|
1281
|
+
:seealso: :meth:`get_map` :meth:`run` :meth:`history`
|
|
1282
|
+
"""
|
|
1283
|
+
if marker is None:
|
|
1284
|
+
marker = {
|
|
1285
|
+
"marker": "+",
|
|
1286
|
+
"markersize": 10,
|
|
1287
|
+
"markerfacecolor": "red",
|
|
1288
|
+
"linewidth": 0,
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
xm = self._x_est
|
|
1292
|
+
P = self._P_est
|
|
1293
|
+
if self._est_vehicle:
|
|
1294
|
+
xm = xm[3:]
|
|
1295
|
+
P = P[3:, 3:]
|
|
1296
|
+
|
|
1297
|
+
# mark the estimate as a point
|
|
1298
|
+
xm = xm.reshape((-1, 2)) # arrange as Nx2
|
|
1299
|
+
plt.plot(xm[:, 0], xm[:, 1], label="estimated landmark", **marker)
|
|
1300
|
+
|
|
1301
|
+
# add an ellipse
|
|
1302
|
+
if ellipse is not None:
|
|
1303
|
+
for i in range(xm.shape[0]):
|
|
1304
|
+
Pi = self.P_est[i : i + 2, i : i + 2]
|
|
1305
|
+
# put ellipse in the legend only once
|
|
1306
|
+
if i == 0:
|
|
1307
|
+
base.plot_ellipse(
|
|
1308
|
+
Pi,
|
|
1309
|
+
centre=xm[i, :],
|
|
1310
|
+
confidence=confidence,
|
|
1311
|
+
inverted=True,
|
|
1312
|
+
label=f"{confidence * 100:.3g}% confidence",
|
|
1313
|
+
**ellipse,
|
|
1314
|
+
)
|
|
1315
|
+
else:
|
|
1316
|
+
base.plot_ellipse(
|
|
1317
|
+
Pi,
|
|
1318
|
+
centre=xm[i, :],
|
|
1319
|
+
confidence=confidence,
|
|
1320
|
+
inverted=True,
|
|
1321
|
+
**ellipse,
|
|
1322
|
+
)
|
|
1323
|
+
# plot_ellipse( P * chi2inv_rtb(opt.confidence, 2), xf, args{:});
|
|
1324
|
+
if block is not None:
|
|
1325
|
+
plt.show(block=block)
|
|
1326
|
+
|
|
1327
|
+
def get_P(self, k=None):
|
|
1328
|
+
"""
|
|
1329
|
+
Get covariance matrices from simulation
|
|
1330
|
+
|
|
1331
|
+
:param k: timestep, defaults to None
|
|
1332
|
+
:type k: int, optional
|
|
1333
|
+
:return: covariance matrix
|
|
1334
|
+
:rtype: ndarray(n,n) or list of ndarray(n,n)
|
|
1335
|
+
|
|
1336
|
+
If ``k`` is given return covariance from simulation timestep ``k``, else
|
|
1337
|
+
return a list of all covariance matrices.
|
|
1338
|
+
|
|
1339
|
+
:seealso: :meth:`get_Pnorm` :meth:`run` :meth:`history`
|
|
1340
|
+
"""
|
|
1341
|
+
if k is not None:
|
|
1342
|
+
return self._history[k].P
|
|
1343
|
+
else:
|
|
1344
|
+
return [h.P for h in self._history]
|
|
1345
|
+
|
|
1346
|
+
def get_Pnorm(self, k=None):
|
|
1347
|
+
"""
|
|
1348
|
+
Get covariance norm from simulation
|
|
1349
|
+
|
|
1350
|
+
:param k: timestep, defaults to None
|
|
1351
|
+
:type k: int, optional
|
|
1352
|
+
:return: covariance matrix norm
|
|
1353
|
+
:rtype: float or ndarray(n)
|
|
1354
|
+
|
|
1355
|
+
If ``k`` is given return covariance norm from simulation timestep ``k``, else
|
|
1356
|
+
return all covariance norms as a 1D NumPy array.
|
|
1357
|
+
|
|
1358
|
+
:seealso: :meth:`get_P` :meth:`run` :meth:`history`
|
|
1359
|
+
"""
|
|
1360
|
+
if k is not None:
|
|
1361
|
+
return np.sqrt(np.linalg.det(self._history[k].P))
|
|
1362
|
+
else:
|
|
1363
|
+
p = [np.sqrt(np.linalg.det(h.P)) for h in self._history]
|
|
1364
|
+
return np.array(p)
|
|
1365
|
+
|
|
1366
|
+
def disp_P(self, P, colorbar=False):
|
|
1367
|
+
"""
|
|
1368
|
+
Display covariance matrix
|
|
1369
|
+
|
|
1370
|
+
:param P: covariance matrix
|
|
1371
|
+
:type P: ndarray(n,n)
|
|
1372
|
+
:param colorbar: add a colorbar
|
|
1373
|
+
:type: bool or dict
|
|
1374
|
+
|
|
1375
|
+
Plot the elements of the covariance matrix as an image. If ``colorbar``
|
|
1376
|
+
is True add a color bar, if `colorbar` is a dict add a color bar with
|
|
1377
|
+
these options passed to colorbar.
|
|
1378
|
+
|
|
1379
|
+
.. note:: A log scale is used.
|
|
1380
|
+
|
|
1381
|
+
:seealso: :meth:`~matplotlib.axes.Axes.imshow` :func:`matplotlib.pyplot.colorbar`
|
|
1382
|
+
"""
|
|
1383
|
+
|
|
1384
|
+
z = np.log10(abs(P))
|
|
1385
|
+
mn = min(z[~np.isinf(z)])
|
|
1386
|
+
z[np.isinf(z)] = mn
|
|
1387
|
+
plt.xlabel("State")
|
|
1388
|
+
plt.ylabel("State")
|
|
1389
|
+
|
|
1390
|
+
plt.imshow(z, cmap="Reds")
|
|
1391
|
+
if colorbar is True:
|
|
1392
|
+
plt.colorbar(label="log covariance")
|
|
1393
|
+
elif isinstance(colorbar, dict):
|
|
1394
|
+
plt.colorbar(**colorbar)
|
|
1395
|
+
|
|
1396
|
+
def get_transform(self, map):
|
|
1397
|
+
"""
|
|
1398
|
+
Transformation from estimated map to true map frame
|
|
1399
|
+
|
|
1400
|
+
:param map: known landmark positions
|
|
1401
|
+
:type map: :class:`LandmarkMap`
|
|
1402
|
+
:return: transform from ``map`` to estimated map frame
|
|
1403
|
+
:rtype: SE2 instance
|
|
1404
|
+
|
|
1405
|
+
Uses a least squares technique to find the transform between the
|
|
1406
|
+
landmark is world frame and the estimated landmarks in the SLAM
|
|
1407
|
+
reference frame.
|
|
1408
|
+
|
|
1409
|
+
:seealso: :func:`~spatialmath.base.transforms2d.points2tr2`
|
|
1410
|
+
"""
|
|
1411
|
+
p = []
|
|
1412
|
+
q = []
|
|
1413
|
+
|
|
1414
|
+
for lm_id in self._landmarks.keys():
|
|
1415
|
+
p.append(map[lm_id])
|
|
1416
|
+
q.append(self.landmark_x(lm_id))
|
|
1417
|
+
|
|
1418
|
+
p = np.array(p).T
|
|
1419
|
+
q = np.array(q).T
|
|
1420
|
+
|
|
1421
|
+
T = base.points2tr2(p, q)
|
|
1422
|
+
return SE2(T)
|
|
1423
|
+
|
|
1424
|
+
|
|
1425
|
+
if __name__ == "__main__":
|
|
1426
|
+
from roboticstoolbox import *
|
|
1427
|
+
|
|
1428
|
+
V = np.diag([0.02, np.deg2rad(0.5)]) ** 2
|
|
1429
|
+
robot = Bicycle(covar=V, animation="car")
|
|
1430
|
+
robot.control = RandomPath(workspace=10)
|
|
1431
|
+
P0 = np.diag([1, 1, 1])
|
|
1432
|
+
V = np.diag([1, 1])
|
|
1433
|
+
ekf = EKF(robot=(robot, V), P0=P0, animate=False)
|
|
1434
|
+
print(ekf)
|
|
1435
|
+
ekf.run_animation(T=20, format="mp4", file="ekf.mp4")
|
|
1436
|
+
|
|
1437
|
+
# from roboticstoolbox import Bicycle
|
|
1438
|
+
|
|
1439
|
+
# ### RVC2: Chapter 6
|
|
1440
|
+
|
|
1441
|
+
# ## 6.1 Dead reckoning
|
|
1442
|
+
|
|
1443
|
+
# ## 6.1.1 Modeling the vehicle
|
|
1444
|
+
# V = np.diag(np.r_[0.02, 0.5*pi/180] ** 2);
|
|
1445
|
+
|
|
1446
|
+
# veh = Bicycle(covar=V)
|
|
1447
|
+
|
|
1448
|
+
# odo = veh.step(1, 0.3)
|
|
1449
|
+
|
|
1450
|
+
# print(veh.x)
|
|
1451
|
+
|
|
1452
|
+
# veh.f([0, 0, 0], odo)
|
|
1453
|
+
|
|
1454
|
+
# # veh.add_driver( RandomPath(10) )
|
|
1455
|
+
|
|
1456
|
+
# # veh.run()
|
|
1457
|
+
|
|
1458
|
+
# ### 6.1.2 Estimating pose
|
|
1459
|
+
# # veh.Fx( [0,0,0], [0.5, 0.1] )
|
|
1460
|
+
|
|
1461
|
+
# P0 = np.diag(np.r_[0.005, 0.005, 0.001]**2);
|
|
1462
|
+
|
|
1463
|
+
# ekf = EKF(veh, V, P0);
|
|
1464
|
+
|
|
1465
|
+
# ekf.run(1000);
|
|
1466
|
+
|
|
1467
|
+
# veh.plot_xy()
|
|
1468
|
+
|
|
1469
|
+
# ekf.plot_xy('r')
|
|
1470
|
+
|
|
1471
|
+
# P700 = ekf.history(700).P
|
|
1472
|
+
|
|
1473
|
+
# sqrt(P700(1,1))
|
|
1474
|
+
|
|
1475
|
+
# ekf.plot_ellipse('g')
|
|
1476
|
+
|
|
1477
|
+
# # 6.2 Map-based localization
|
|
1478
|
+
# # randinit
|
|
1479
|
+
# # map = LandmarkMap(20, 10)
|
|
1480
|
+
|
|
1481
|
+
# # map.plot()
|
|
1482
|
+
|
|
1483
|
+
# # W = diag([0.1, 1*pi/180].^2);
|
|
1484
|
+
|
|
1485
|
+
# # sensor = RangeBearingSensor(veh, map, 'covar', W)
|
|
1486
|
+
|
|
1487
|
+
# # [z,i] = sensor.reading()
|
|
1488
|
+
|
|
1489
|
+
# # map.landmark(17)
|
|
1490
|
+
|
|
1491
|
+
# # randinit
|
|
1492
|
+
# # map = LandmarkMap(20);
|
|
1493
|
+
# # veh = Bicycle('covar', V);
|
|
1494
|
+
# # veh.add_driver( RandomPath(map.dim) );
|
|
1495
|
+
# # sensor = RangeBearingSensor(veh, map, 'covar', W, 'angle', ...
|
|
1496
|
+
# # [-pi/2 pi/2], 'range', 4, 'animate');
|
|
1497
|
+
# # ekf = EKF(veh, V, P0, sensor, W, map);
|
|
1498
|
+
|
|
1499
|
+
# # ekf.run(1000);
|
|
1500
|
+
# # map.plot()
|
|
1501
|
+
# # veh.plot_xy();
|
|
1502
|
+
# # ekf.plot_xy('r');
|
|
1503
|
+
# # ekf.plot_ellipse('k')
|
|
1504
|
+
|
|
1505
|
+
# # 6.3 Creating a map
|
|
1506
|
+
# # randinit
|
|
1507
|
+
# # map = LandmarkMap(20);
|
|
1508
|
+
# # veh = Bicycle(); error free vehicle
|
|
1509
|
+
# # veh.add_driver( RandomPath(map.dim) );
|
|
1510
|
+
# # W = diag([0.1, 1*pi/180].^2);
|
|
1511
|
+
# # sensor = RangeBearingSensor(veh, map, 'covar', W);
|
|
1512
|
+
# # ekf = EKF(veh, [], [], sensor, W, []);
|
|
1513
|
+
|
|
1514
|
+
# # ekf.run(1000);
|
|
1515
|
+
|
|
1516
|
+
# # map.plot();
|
|
1517
|
+
# # ekf.plot_map('g');
|
|
1518
|
+
# # veh.plot_xy('b');
|
|
1519
|
+
|
|
1520
|
+
# # ekf.landmarks(:,6)
|
|
1521
|
+
|
|
1522
|
+
# # ekf.x_est(19:20)'
|
|
1523
|
+
|
|
1524
|
+
# # ekf.P_est(19:20,19:20)
|
|
1525
|
+
|
|
1526
|
+
# # 6.4 EKF SLAM
|
|
1527
|
+
# # randinit
|
|
1528
|
+
# # P0 = diag([.01, .01, 0.005].^2);
|
|
1529
|
+
# # map = LandmarkMap(20);
|
|
1530
|
+
# # veh = Bicycle('covar', V);
|
|
1531
|
+
# # veh.add_driver( RandomPath(map.dim) );
|
|
1532
|
+
# # sensor = RangeBearingSensor(veh, map, 'covar', W);
|
|
1533
|
+
# # ekf = EKF(veh, V, P0, sensor, W, []);
|
|
1534
|
+
|
|
1535
|
+
# # ekf.run(1000);
|
|
1536
|
+
|
|
1537
|
+
# # map.plot();
|
|
1538
|
+
# # ekf.plot_map('g');
|
|
1539
|
+
# # ekf.plot_xy('r');
|
|
1540
|
+
# # veh.plot_xy('b');
|
|
1541
|
+
|
|
1542
|
+
# # 6.6 Pose-graph SLAM
|
|
1543
|
+
# # syms x_i y_i theta_i x_j y_j theta_j x_m y_m theta_m assume real
|
|
1544
|
+
# # xi_e = inv( SE2(x_m, y_m, theta_m) ) * inv( SE2(x_i, y_i, theta_i) ) * SE2(x_j, y_j, theta_j);
|
|
1545
|
+
# # fk = simplify(xi_e.xyt);
|
|
1546
|
+
|
|
1547
|
+
# # jacobian ( fk, [x_i y_i theta_i] );
|
|
1548
|
+
# # Ai = simplify (ans)
|
|
1549
|
+
|
|
1550
|
+
# # pg = PoseGraph('pg1.g2o')
|
|
1551
|
+
|
|
1552
|
+
# # clf
|
|
1553
|
+
# # pg.plot()
|
|
1554
|
+
|
|
1555
|
+
# # pg.optimize('animate')
|
|
1556
|
+
|
|
1557
|
+
# # pg = PoseGraph('killian-small.toro');
|
|
1558
|
+
|
|
1559
|
+
# # pg.plot()
|
|
1560
|
+
|
|
1561
|
+
# # pg.optimize()
|
|
1562
|
+
|
|
1563
|
+
# # 6.7 Particle filter
|
|
1564
|
+
# # randinit
|
|
1565
|
+
# # map = LandmarkMap(20);
|
|
1566
|
+
# # W = diag([0.1, 1*pi/180].^2);
|
|
1567
|
+
# # veh = Bicycle('covar', V);
|
|
1568
|
+
# # veh.add_driver( RandomPath(10) );
|
|
1569
|
+
|
|
1570
|
+
# # V = diag([0.005, 0.5*pi/180].^2);
|
|
1571
|
+
# # sensor = RangeBearingSensor(veh, map, 'covar', W);
|
|
1572
|
+
|
|
1573
|
+
# # Q = diag([0.1, 0.1, 1*pi/180]).^2;
|
|
1574
|
+
|
|
1575
|
+
# # L = diag([0.1 0.1]);
|
|
1576
|
+
|
|
1577
|
+
# # pf = ParticleFilter(veh, sensor, Q, L, 1000);
|
|
1578
|
+
|
|
1579
|
+
# # pf.run(1000);
|
|
1580
|
+
|
|
1581
|
+
# # map.plot();
|
|
1582
|
+
# # veh.plot_xy('b');
|
|
1583
|
+
|
|
1584
|
+
# # clf
|
|
1585
|
+
# # pf.plot_xy('r');
|
|
1586
|
+
|
|
1587
|
+
# # clf
|
|
1588
|
+
# # plot(pf.std(1:100,:))
|
|
1589
|
+
|
|
1590
|
+
# # clf
|
|
1591
|
+
# # pf.plot_pdf()
|
|
1592
|
+
|
|
1593
|
+
# # 6.8 Application: Scanning laser rangefinder
|
|
1594
|
+
|
|
1595
|
+
# # Laser odometry
|
|
1596
|
+
# # pg = PoseGraph('killian.g2o', 'laser');
|
|
1597
|
+
|
|
1598
|
+
# # [r, theta] = pg.scan(2580);
|
|
1599
|
+
# # about r theta
|
|
1600
|
+
|
|
1601
|
+
# # clf
|
|
1602
|
+
# # polar(theta, r)
|
|
1603
|
+
|
|
1604
|
+
# # [x,y] = pol2cart (theta, r);
|
|
1605
|
+
# # plot (x, y, '.')
|
|
1606
|
+
|
|
1607
|
+
# # p2580 = pg.scanxy(2580);
|
|
1608
|
+
# # p2581 = pg.scanxy(2581);
|
|
1609
|
+
# # about p2580
|
|
1610
|
+
|
|
1611
|
+
# # T = icp( p2581, p2580, 'verbose' , 'T0', transl2(0.5, 0), 'distthresh', 3)
|
|
1612
|
+
|
|
1613
|
+
# # pg.time(2581)-pg.time(2580)
|
|
1614
|
+
|
|
1615
|
+
# # Laser-based map building
|
|
1616
|
+
# # map = pg.scanmap();
|
|
1617
|
+
# # pg.plot_occgrid(map)
|