diff --git a/README.md b/README.md deleted file mode 100644 index 846f0d84..00000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# project - diff --git a/Src/hybrid_astar_planner-main/.vscode/c_cpp_properties.json b/Src/hybrid_astar_planner-main/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..2139473a --- /dev/null +++ b/Src/hybrid_astar_planner-main/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux", + "browse": { + "databaseFilename": "", + "limitSymbolsToIncludedHeaders": true + }, + "includePath": [ + "${workspaceFolder}/**", + "/opt/ros/melodic/include", + "/opt/ros/melodic/include/ompl-1.4" + ] + + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/.vscode/settings.json b/Src/hybrid_astar_planner-main/.vscode/settings.json new file mode 100644 index 00000000..5809a907 --- /dev/null +++ b/Src/hybrid_astar_planner-main/.vscode/settings.json @@ -0,0 +1,73 @@ +{ + "python.autoComplete.extraPaths": [ + "/home/dengpw/catkin_ws/devel/lib/python2.7/dist-packages", + "/opt/ros/melodic/lib/python2.7/dist-packages" + ], + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "complex": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "list": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "hash_map": "cpp", + "hash_set": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "numeric": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "system_error": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "algorithm": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "random": "cpp", + "set": "cpp", + "string": "cpp", + "string_view": "cpp", + "*.ipp": "cpp", + "*.txx": "cpp", + "valarray": "cpp" + } +} \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/CMakeLists.txt b/Src/hybrid_astar_planner-main/CMakeLists.txt new file mode 100644 index 00000000..fe6e5296 --- /dev/null +++ b/Src/hybrid_astar_planner-main/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 3.0.2) +project(hybrid_astar_planner) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_COMPILER "g++") + +# add_subdirectory(test_the_plugin) + +find_package(catkin REQUIRED COMPONENTS + geometry_msgs + pluginlib + costmap_2d + roscpp + nav_core + tf2_ros + ompl +) + +catkin_package( + INCLUDE_DIRS include + LIBRARIES ${PROJECT_NAME} + geometry_msgs + pluginlib + roscpp + nav_core + tf2_ros + ompl +) + +include_directories( + include + test_the_plugin/include + ${catkin_INCLUDE_DIRS} + ${OMPL_INCLUDE_DIRS} +) + +# find_package(ompl REQUIRED) + +# if(NOT OMPL_FOUND) +# message(AUTHOR_WARNING,"Open Motion Planning Library not found") +# endif(NOT OMPL_FOUND) + + +add_executable(test_planner test_the_plugin/src/test.cpp test_the_plugin/src/test_plugins.cpp) +target_link_libraries(test_planner ${catkin_LIBRARIES}) + +add_executable(tf_test_broadcaster test_the_plugin/src/tf_broadcaster.cpp) +target_link_libraries(tf_test_broadcaster ${catkin_LIBRARIES}) + +add_library(${PROJECT_NAME} + src/planner_core.cpp + src/hybrid_astar.cpp + src/node2d.cpp + src/a_start.cpp + src/visualize.cpp + src/node3d.cpp + src/hybrid_astar.cpp + src/algorithm.cpp + src/dubins.cpp + src/ReedsShepp.cpp +) +target_link_libraries(${PROJECT_NAME} ${OMPL_LIBRARIES}) + +install(FILES bgp_plugin.xml + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/LICENSE b/Src/hybrid_astar_planner-main/LICENSE new file mode 100644 index 00000000..5b18a23b --- /dev/null +++ b/Src/hybrid_astar_planner-main/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2021, dengpw +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Src/hybrid_astar_planner-main/README.md b/Src/hybrid_astar_planner-main/README.md new file mode 100644 index 00000000..3deffac1 --- /dev/null +++ b/Src/hybrid_astar_planner-main/README.md @@ -0,0 +1,41 @@ +# hybrid_astar_planner + +This is a global planner plugin of ROS move_base package. + +## Introduction +Traditional robot navigation algorithms (such as the logistics storage robot used by Jingdong or Amazon) +mostly use a * algorithm or Dijkstra search algorithm to planning its trajectory after the map is gridded. +Most of them are differential models. Obviously, this kind of path is still difficult to realize for traditional +four-wheel vehicles whitch has nonholonomic constraint (vehicles with Ackerman steering mechanism). +So I designed a hybrid a * plug-in for ROS as my graduation project + +## How to Use + +### Dependencies +Install all dependencies +* [Open Motion Planning Library (OMPL)](http://ompl.kavrakilab.org/) +* [ros_map_server](http://wiki.ros.org/map_server) + +### Setup + +Run the following command to clone, build, and launch the package (requires a sources ROS environment): + +``` +sudo apt install libompl-dev \ +&& mkdir -p ~/catkin_ws/src \ +&& cd ~/catkin_ws/src \ +&& git clone https://github.com/dengpw/hybrid_astar_planner.git \ +&& cd .. \ +&& catkin_make \ +&& source devel/setup.bash \ +&& rospack profile \ +``` + +You can run the folling command to test whether the plug-in is install propely +``` +&& roslaunch hybrid_astar_planner test.launch +``` +It can run a static teajectory planner using hybrid A* +If everything run fine,you can use this plugin in ROS naviagation package by making a special declaration before starting the launch file: + < `param name="base_global_planner" value="global_planner/GlobalPlanner"` / > + < `param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS"` / > \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/hybrid_astar_planner_plugin.xml b/Src/hybrid_astar_planner-main/hybrid_astar_planner_plugin.xml new file mode 100644 index 00000000..d084a05d --- /dev/null +++ b/Src/hybrid_astar_planner-main/hybrid_astar_planner_plugin.xml @@ -0,0 +1,7 @@ + + + + A implementation of a based planner using Hybrid A* + + + diff --git a/Src/hybrid_astar_planner-main/include/ReedsShepp.h b/Src/hybrid_astar_planner-main/include/ReedsShepp.h new file mode 100644 index 00000000..a070c084 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/ReedsShepp.h @@ -0,0 +1,90 @@ +/********************************************************************* +* +* Software License Agreement (BSD License) +* +* Copyright (c) 2016, Guan-Horng Liu. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* Author: Guan-Horng Liu +*********************************************************************/ + +#ifndef SPACES_REEDS_SHEPP_STATE_SPACE_ +#define SPACES_REEDS_SHEPP_STATE_SPACE_ + +#include +#include + +class ReedsSheppStateSpace +{ +public: + + /** \brief The Reeds-Shepp path segment types */ + enum ReedsSheppPathSegmentType { RS_NOP=0, RS_LEFT=1, RS_STRAIGHT=2, RS_RIGHT=3 }; + + /** \brief Reeds-Shepp path types */ + static const ReedsSheppPathSegmentType reedsSheppPathType[18][5]; + + /** \brief Complete description of a ReedsShepp path */ + class ReedsSheppPath + { + public: + ReedsSheppPath(const ReedsSheppPathSegmentType* type=reedsSheppPathType[0], + double t=std::numeric_limits::max(), double u=0., double v=0., + double w=0., double x=0.); + + double length() const { return totalLength_; } + + /** Path segment types */ + const ReedsSheppPathSegmentType* type_; + /** Path segment lengths */ + double length_[5]; + /** Total length */ + double totalLength_; + }; + + ReedsSheppStateSpace(double turningRadius) : rho_(turningRadius) {} + + double distance(double q0[3], double q1[3]); + + std::vector type(double q0[3], double q1[3]); + + void sample(double q0[3], double q1[3], double step_size, double &length, std::vector > &points); + + /** \brief Return the shortest Reeds-Shepp path from SE(2) state state1 to SE(2) state state2 */ + ReedsSheppPath reedsShepp(double q0[3], double q1[3]); + +protected: + void interpolate(double q0[3], ReedsSheppPath &path, double seg, double s[3]); + + /** \brief Turning radius */ + double rho_; +}; + +#endif \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/algorithm.h b/Src/hybrid_astar_planner-main/include/algorithm.h new file mode 100644 index 00000000..c8d07350 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/algorithm.h @@ -0,0 +1,32 @@ +#ifndef _ALGORITHM_H +#define _ALGORITHM_H + +#include +#include +#include +#include +#include +#include "node3d.h" +#include "node2d.h" +#include +#include +#include +typedef ompl::base::SE2StateSpace::StateType State; +namespace hybrid_astar_planner { +// OPEN LIST AS BOOST IMPLEMENTATION +struct CompareNodes { + // Sorting 3D nodes by increasing C value - the total estimated cost + bool operator()(const Node3D* lhs, const Node3D* rhs) const { + return lhs->getF() > rhs->getF(); + } + // Sorting 2D nodes by increasing C value - the total estimated cost + bool operator()(const Node2D* lhs, const Node2D* rhs) const { + return lhs->getF() > rhs->getF(); + } +}; +Node3D* dubinsShot(Node3D& start, Node3D& goal, costmap_2d::Costmap2D* costmap); +Node3D* reedsSheppShot(Node3D& start, Node3D& goal, costmap_2d::Costmap2D* costmap); +void updateH(Node3D& start, const Node3D& goal, Node2D* nodes2D, float* dubinsLookup, int width, int height, float inspireAstar); +} + +#endif //end of algorithm.h diff --git a/Src/hybrid_astar_planner-main/include/astar.h b/Src/hybrid_astar_planner-main/include/astar.h new file mode 100644 index 00000000..0be55b43 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/astar.h @@ -0,0 +1,58 @@ +#ifndef _ASTAR_H +#define _ASTAR_H + +#include +#include "algorithm.h" +#include "expander.h" +#include "node2d.h" +#include +#include +namespace hybrid_astar_planner { +class Index { + public: + Index(int a,float b) { + i = a; + cost = b; + } + int i; + float cost; + }; + +class astar : public Expander +{ + + public: + astar(std::string frame_id, costmap_2d::Costmap2D* _costmap) + :Expander(frame_id, _costmap) { + + } + + /** + * @brief Find the path between the start pose and goal pose + * @param start the reference of start pose + * @param goal the reference of goal pose + * @param cells_x the number of the cells of the costmap in x axis + * @param cells_y the number of the cells of the costmap in y axis + * @param plan the refrence of plan; + * @return true if a valid plan was found. + */ + bool calculatePath(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, + int cells_x, int cells_y, std::vector& plan ,ros::Publisher& pub, visualization_msgs::MarkerArray& pathNodes ); + ~astar(){ } + private: + + std::vector gatAdjacentPoints(int cells_x, int cells_y, const unsigned char* charMap, Node2D* pathNode2D, Node2D *point ); + + /** + * @brief transform the 2Dnode to geometry_msgs::PoseStamped + * @param node the ptr of node + * @param plan the refrence of plan + */ + void nodeToPlan(Node2D* node, std::vector& plan); + /* data */ +}; + + +}//end of namespace hybrid_astar_planner + +#endif //the end of astar.h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/constants.h b/Src/hybrid_astar_planner-main/include/constants.h new file mode 100644 index 00000000..6aeb525d --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/constants.h @@ -0,0 +1,84 @@ +#ifndef _CONSTANTS +#define _CONSTANTS + +#include + +namespace hybrid_astar_planner { + +namespace Constants { +/// A flag to toggle reversing (true = on; false = off) +/// 设置是否允许车辆后退的标志位 true表示可以倒退;false表示只能前进不能倒退 +static const bool reverse = true; + +/// [#] --- Limits the maximum search depth of the algorithm, possibly terminating without the solution +/// 最大迭代次数 +static const int iterations = 30000; + +/// [m] --- Uniformly adds a padding around the vehicle +/// 膨胀范围 +static const double bloating = 0; + +/// [m] --- The width of the vehicle +static const double width = 0.18 + 2 * bloating;//车的宽度 + +/// [m] --- The length of the vehicle +static const double length = 0.22 + 2 * bloating;//车的长度 + +/* +* 车模需要转弯半径为0.75米的 +* 车身长度需要0.15m(长) * 0.16m(轮宽) +*/ +/// [m] --- the Minimum turning radius 车辆最小转弯半径 +static const double r = 1; + +/// [m] --- The number of discretizations in heading +/// 车体朝向的离散数量 +// static const int headings = 72; +static const int headings = 72; +// const float dy[] = { 0, -0.0415893, 0.0415893}; +// const float dx[] = { 0.7068582, 0.705224, 0.705224}; +// const float dt[] = { 0, 0.1178097, -0.1178097}; + +const float dy[] = { 0, -0.005198, 0.005198}; +const float dx[] = { 0.0883573, 0.088153, 0.088153}; +const float dt[] = { 0, 0.1178097, -0.1178097}; +/// [°] --- The discretization value of the heading (goal condition) +/// 朝向离散度数(以度表示) +static const float deltaHeadingDeg = 360 / (float)headings; + +/// [c*M_PI] --- The discretization value of heading (goal condition) +static const float deltaHeadingRad = 2 * M_PI / (float)headings; //朝向离散步长(以弧度表示) + +/// [c*M_PI] --- The heading part of the goal condition +static const float deltaHeadingNegRad = 2 * M_PI - deltaHeadingRad; + +/// A flag to toggle the connection of the path via Dubin's shot (true = on; false = off) +static const bool dubinsShot = false; //切换Dubin路径的开关 + +/// A flag to toggle the connection of the path via reedsSheppShot (true = on; false = off) +static const bool reedsSheppShot = true; //切换Dubin路径的开关 + +/// A flag to toggle the Dubin's heuristic, this should be false, if reversing is enabled (true = on; false = off) +static const bool dubins = false;//Dubin路径的切换开关: 若车子可以倒退,值为false +// ___________________ +// HEURISTIC CONSTANTS + +/// [#] --- A factor to ensure admissibility of the holonomic with obstacles heuristic +static const float factor2D = sqrt(5) / sqrt(2) + 1; +/// [#] --- A movement cost penalty for turning (choosing non straight motion primitives) +static const float penaltyTurning = 1.05; +/// [#] --- A movement cost penalty for reversing (choosing motion primitives > 2) +static const float penaltyReversing = 1.5; +/// [#] --- A movement cost penalty for change of direction (changing from primitives < 3 to primitives > 2) +static const float penaltyCOD = 1.5; +/// [m] --- The distance to the goal when the analytical solution (Dubin's shot) first triggers +static const float dubinsShotDistance = 100; +/// [m] --- The step size for the analytical solution (Dubin's shot) primarily relevant for collision checking +static const float dubinsStepSize = 0.088; + +} + + +} + +#endif \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/dubins.h b/Src/hybrid_astar_planner-main/include/dubins.h new file mode 100644 index 00000000..dd5eafa6 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/dubins.h @@ -0,0 +1,218 @@ +/*! + \file dubins.h + \brief A dubins path class for finding analytical solutions to the problem of the shortest path. + It has been copied from https://github.com/AndrewWalker/Dubins-Curves/ under the WTFPL. + Please refer to the author in case of questions. + \author Andrew Walker +*/ +// Copyright (c) 2008-2014, Andrew Walker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#ifndef DUBINS_H +#define DUBINS_H + +// Path types +#define LSL (0) +#define LSR (1) +#define RSL (2) +#define RSR (3) +#define RLR (4) +#define LRL (5) + +// Error codes +#define EDUBOK (0) // No error +#define EDUBCOCONFIGS (1) // Colocated configurations +#define EDUBPARAM (2) // Path parameterisitation error +#define EDUBBADRHO (3) // the rho value is invalid +#define EDUBNOPATH (4) // no connection between configurations with this word + +namespace hybrid_astar_planner { + +// The various types of solvers for each of the path types +typedef int (*DubinsWord)(double, double, double, double* ); + +// A complete list of the possible solvers that could give optimal paths +extern DubinsWord dubins_words[]; + +typedef struct +{ + double qi[3]; // the initial configuration + double param[3]; // the lengths of the three segments + double rho; // model forward velocity / model angular velocity + int type; // path type. one of LSL, LSR, ... +} DubinsPath; + +/** + * Callback function for path sampling + * + * @note the q parameter is a configuration + * @note the t parameter is the distance along the path + * @note the user_data parameter is forwarded from the caller + * @note return non-zero to denote sampling should be stopped + */ + +/** + * @brief 回调函数: + * q:一个构型(configuration) + * t:路径长度 + * user_data:传递的数据 + * + */ +typedef int (*DubinsPathSamplingCallback)(double q[3], double t, void* user_data); + + +/** + * Generate a path from an initial configuration to + * a target configuration, with a specified maximum turning + * radii + * + * A configuration is (x, y, theta), where theta is in radians, with zero + * along the line x = 0, and counter-clockwise is positive + * + * @param q0 - a configuration specified as an array of x, y, theta + * @param q1 - a configuration specified as an array of x, y, theta + * @param rho - turning radius of the vehicle (forward velocity divided by maximum angular velocity) + * @param path - the resultant path + * @return - non-zero on error + */ + +/** + * @brief 从初始构型(始点)q0构建一条到q1的dubins路径,最大转向半径为rho(单位为米?) + * + * @param q0 起点 + * @param q1 目标点 + * @param rho 转向半径 + * @param path 构建的路径点 + * @return int 返回值:非0表示出错;0表示正常 + */ +int dubins_init( double q0[3], double q1[3], double rho, DubinsPath* path); + +/** + * Calculate the length of an initialised path + * + * @param path - the path to find the length of + */ +/** + * @brief 计算一条经过初始化阶段(归一化)的路径的长度 + * + * @param path 经过dubins_init()函数计算出来的路径点 + * @return double 返回值表示该路径的长度 + */ +double dubins_path_length( DubinsPath* path ); + +/** + * Extract an integer that represents which path type was used + * + * @param path - an initialised path + * @return - one of LSL, LSR, RSL, RSR, RLR or LRL (ie/ 0-5 inclusive) + */ +/** + * @brief 计算一段路径的类型 + * + * @param path:路径点 + * @return int:路径类型,整数表示LSL, LSR, RSL, RSR, RLR or LRL(用整数0-5之一表示结果) + */ +int dubins_path_type( DubinsPath * path ); + +/** + * Calculate the configuration along the path, using the parameter t + * + * @param path - an initialised path + * @param t - a length measure, where 0 <= t < dubins_path_length(path) + * @param q - the configuration result + * @returns - non-zero if 't' is not in the correct range + */ + +/** + * @brief 使用参数t计算沿路径path的构型(位姿) + * + * @param path 路径点 + * @param t: 长度单位,范围为 0 <= t <= dubins_path_length(path) + * @param q: 计算结果 + * @return int: 返回值,非0值表示出错,0表示正常 + */ +int dubins_path_sample( DubinsPath* path, double t, double q[3]); + +/** + * Walk along the path at a fixed sampling interval, calling the + * callback function at each interval + * + * @param path - the path to sample + * @param cb - the callback function to call for each sample + * @param user_data - optional information to pass on to the callback + * @param stepSize - the distance along the path for subsequent samples + */ +/** + * @brief 用固定步长在路径path进行遍历,每个区间调用回调函数callback一次 + * + * @param path 路径 + * @param cb 回调函数 + * @param stepSize 步长 + * @param user_data 用户数据,用于交换数据 + * @return int 返回值:非0表示出错;0表示正常 + */ +int dubins_path_sample_many( DubinsPath* path, DubinsPathSamplingCallback cb, double stepSize, void* user_data ); + +/** + * Convenience function to identify the endpoint of a path + * + * @param path - an initialised path + * @param q - the configuration result + */ +/** + * @brief 用于提取路径的终点 + * + * @param path 路径 + * @param q 提取的终点 + * @return int 返回值:非0表示出错;0表示正常 + */ +int dubins_path_endpoint( DubinsPath* path, double q[3] ); + +/** + * Convenience function to extract a subset of a path + * + * @param path - an initialised path + * @param t - a length measure, where 0 < t < dubins_path_length(path) + * @param newpath - the resultant path + */ +/** + * @brief 提取路径的一段子集的函数 + * + * @param path 给定的路径 + * @param t 长度,范围 0 < t < dubins_path_length(path) + * @param newpath 提取的子路径 + * @return int 返回值:非0表示出错;0表示正常 + */ +int dubins_extract_subpath( DubinsPath* path, double t, DubinsPath* newpath ); + +// Only exposed for testing purposes +//构造不同类型的路径的函数 +int dubins_LSL( double alpha, double beta, double d, double* outputs ); +int dubins_RSR( double alpha, double beta, double d, double* outputs ); +int dubins_LSR( double alpha, double beta, double d, double* outputs ); +int dubins_RSL( double alpha, double beta, double d, double* outputs ); +int dubins_LRL( double alpha, double beta, double d, double* outputs ); +int dubins_RLR( double alpha, double beta, double d, double* outputs ); +void dubins_segment( double t, double qi[3], double qt[3], int type); +int dubins_init_normalised( double alpha, double beta, double d, DubinsPath* path); +double mod2pi( double theta ); +double fmodr( double x, double y); +} + +#endif //end of dubins.h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/expander.h b/Src/hybrid_astar_planner-main/include/expander.h new file mode 100644 index 00000000..00a2e672 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/expander.h @@ -0,0 +1,35 @@ +#ifndef _EXPANDER_H +#define _EXPANDER_H +#include +#include +#include +#include +#include +#include +#include +namespace hybrid_astar_planner { + +/** + * @brief the base class of astar or hybrid astar planner +*/ +class Expander +{ + + public: + Expander(std::string frame_id, costmap_2d::Costmap2D* _costmap) + :frame_id_(frame_id), costmap(_costmap) { + + } + + virtual bool calculatePath(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, + int cells_x, int cells_y, std::vector& plan ,ros::Publisher& pub, visualization_msgs::MarkerArray& pathNodes) = 0; + virtual ~Expander() {} + protected: + std::string frame_id_; + costmap_2d::Costmap2D* costmap; + /* data */ +}; + + +} //end of namespace hybrid_astar_planner +#endif //end of expander.h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/hybrid_astar.h b/Src/hybrid_astar_planner-main/include/hybrid_astar.h new file mode 100644 index 00000000..1108fb43 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/hybrid_astar.h @@ -0,0 +1,89 @@ +#ifndef _HYBRID_ASTAR_H +#define _HYBRID_ASTAR_H + +#include +#include "algorithm.h" +#include "expander.h" +#include "node3d.h" +#include +#include +// #define TEST +#define point_accuracy 0.5 +#define theta_accuracy 2 +namespace hybrid_astar_planner { + +class hybridAstar : public Expander +{ + + public: + /** + * @brief Default constructor for the HybridAStarPlanner object + */ + hybridAstar(std::string frame_id, costmap_2d::Costmap2D* _costmap) + :Expander(frame_id, _costmap) { + + } + + /** + * @brief Find the path between the start pose and goal pose + * @param start the reference of start pose + * @param goal the reference of goal pose + * @param cells_x the number of the cells of the costmap in x axis + * @param cells_y the number of the cells of the costmap in y axis + * @param plan the refrence of plan; + * @return true if a valid plan was found. + */ + bool calculatePath( + const geometry_msgs::PoseStamped& start, + const geometry_msgs::PoseStamped& goal, + int cellsX, int cellsY, std::vector& plan, + ros::Publisher& pub, visualization_msgs::MarkerArray& pathNodes); + + /** + * @brief Default deconstructor for the HybridAStarPlanner object + */ + ~hybridAstar(){ } + + private: + + /** + * @brief Get the adjacent pose of a given pose + * @param cells_x the number of the cells of the costmap in x axis + * @param cells_y the number of the cells of the costmap in y axis + * @param charMap + */ + std::vector gatAdjacentPoints(int dir, int cells_x, int cells_y, const unsigned char* charMap, Node3D *point); + + /** + * @brief judge whether is reach the goal pose + * @param node the refrence of the node + * @param goalPose the goal of the planner + * @return true if reach the goal + */ + bool reachGoal(Node3D* node, Node3D* goalPose); + + /** + * @brief get the index of node + * @param x the x position axis of the node + * @param y the y position axis of the node + * @param cells_x the scale of cells in x axis + * @param t the depth of the 3D nodes + * @return the index of node + */ + int calcIndix(float x, float y, int cells_x, float t); + + /** + * @brief transform the 2Dnode to geometry_msgs::PoseStamped + * @param node the ptr of node + * @param plan the refrence of plan + */ + void nodeToPlan(Node3D* node, std::vector& plan); + std::unique_ptr grid_a_star_heuristic_generator_; +}; + + + + +}//end of namespace hybrid_astar_planner + +#endif //the end of astar.h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/node2d.h b/Src/hybrid_astar_planner-main/include/node2d.h new file mode 100644 index 00000000..9ad298b2 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/node2d.h @@ -0,0 +1,99 @@ +#ifndef _NODE2D_H +#define _NODE2D_H + +#include +#include +#include +namespace hybrid_astar_planner { + +class Node2D +{ +public: + Node2D(): Node2D(0, 0, 999, 0, nullptr) {} + Node2D(int _x , int _y, float _g = 999, float _h = 0, Node2D* _perd = nullptr): + x(_x), y(_y), g(_g), h(_h), perd(_perd), o(false), c(false) + { + index = -1; + } + ~Node2D(){} + + void setX(int _x) { x = _x; } + void setY(int _y) { y = _y; } + void setCost(unsigned int C) { cost = C; } + void setG(float _g) { g = _g; } + void setH(float _h) { h = _h; } + void setClosedSet() { c = true; o = false; } + void setOpenSet() { o = true; } + void setPerd(Node2D* _perd) { perd = _perd; } + void setPerd_(std::shared_ptr _perd) { perd_node = _perd; } + int getX(void) { return x; } + int getY(void) { return y; } + float getF(void) const { return g + h; } + float calcG(Node2D const *partent); + float getG() const { return g; } + float calcH(Node2D const *goal); + int getindex(int width) { return (y * width + x); } + int getCost() {return cost;} + bool isOpenSet() { return o; } + bool isClosedSet() { return c; } + Node2D* getPerd() { return perd; } + void SetPathCost(const float path_cost) { + g = path_cost; + } + private: + // float cost_ = 999; + /// the x position + int x; + /// the y position + int y; + /// the cost of current node + unsigned int cost; + /// the cost-so-far + float g; + /// the cost-to-go + float h; + /// the index of the node in the 2D array + int index; + /// the open value + bool o; + /// the closed value + bool c; + /// the discovered value + bool d; + /// the predecessor pointer + Node2D* perd; + std::shared_ptr perd_node = nullptr; +}; + +class GridSearch { + public: + GridSearch() + { + + } + ~GridSearch() + { + + } + std::vector> getAdjacentPoints(int cells_x, + int cells_y, const unsigned char* charMap, std::shared_ptr point); + + std::unordered_map> GenerateDpMap( + const double goal_x, const double goal_y, + costmap_2d::Costmap2D* costmap); + // std::unordered_map> dp_map_; + private: + + // std::unordered_map> dp_map_; + struct cmp { + // Sorting 3D nodes by increasing C value - the total estimated cost + bool operator()(const std::pair& left, + const std::pair& right) const { + return left.second >= right.second; + } + }; +}; + +}//end of namespace hybrid_astar_planner + +#endif //end of node2d.h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/node3d.h b/Src/hybrid_astar_planner-main/include/node3d.h new file mode 100644 index 00000000..a54b9c9c --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/node3d.h @@ -0,0 +1,87 @@ +#ifndef _NODE3D_H +#define _NODE3D_H +#include "constants.h" +#include +namespace hybrid_astar_planner { +class Node3D +{ +public: + Node3D(): Node3D(0, 0, 0, 999, 0, false, nullptr) {} + Node3D(float _x , float _y, float t, float _g = 999, float _h = 0, bool _reverse = false, Node3D* _perd = nullptr): + x(_x), y(_y), g(_g), h(_h), reverse(_reverse), perd(_perd), o(false), c(false) + { + setT(t); + index = -1; + } + ~Node3D(){} + + void setX(float _x) { x = _x; } + void setY(float _y) { y = _y; } + void setCost(unsigned int C) { cost = C; } + void setT(float _t); + void setG(float _g) { g = _g; } + void setH(float _h) { h = _h; } + void setClosedSet() { c = true; o = false; } + void setOpenSet() { o = true; } + void setPerd(Node3D* _perd) { perd = _perd; } + void setReverse(bool r) { reverse = r; } + float getX(void) const { return x; } + float getY(void) const { return y; } + float getT(void) const { return t * Constants::deltaHeadingRad; } + float getTheta(void) const { return theta; } + float getF(void) const { return g + h; } + int getCost() {return cost;} + /** + * @brief caculate the G value of the node + * @return the G value of the node + * G值为状态空间中从初始节点到当前此节点的实际代价 + * + */ + float calcG(void); + float getG() const { return g; } + float calcH(Node3D const *goal); + int getindex(int width, int depth, float resolution, unsigned int dx, unsigned int dy) { this->index = (int(x/resolution + dx) * width + int(y/resolution + dy))*depth + t; return index;}//这里的resolution变动了 + bool isOpenSet() { return o; } + bool isClosedSet() { return c; } + bool isReverse() { return reverse; } + Node3D* getPerd() { return perd; } + // RANGE CHECKING + /// Determines whether it is appropriate to find a analytical solution. + bool isInRange(const Node3D& goal) const;//检测是否可以分析方法找到解 + + // CUSTOM OPERATORS + /// Custom operator to compare nodes. Nodes are equal if their x and y position as well as heading is similar. + bool operator == (const Node3D& rhs) const;//位置相同且朝向相似则认为是同一节点 + + private: + /// the x position + float x; + /// the y position + float y; + /// the t position + int t; + /// the cost of this node in costmap + unsigned int cost; + /// the theta of this node + float theta; + /// the cost-so-far + float g; + /// the cost-to-go + float h; + /// the index of the node in the 3D array + int index; + /// the open value + bool o; + /// the closed value + bool c; + /// the discovered value + bool d; + /// the flag of node,Indicates whether the vehicle is in reverse + bool reverse; + /// the predecessor pointer + Node3D* perd; +}; + +}//end of namespace hybrid_astar_planner + +#endif //end of node3d.h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/include/planner_core.h b/Src/hybrid_astar_planner-main/include/planner_core.h new file mode 100644 index 00000000..c35beb5d --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/planner_core.h @@ -0,0 +1,142 @@ +#ifndef _PLANNERCORE_H +#define _PLANNERCORE_H +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *********************************************************************/ +// #define POT_HIGH 1.0e10 // unassigned cell potential +#include +#include +#include +#include +#include +#include "node2d.h" +#include "node3d.h" +namespace hybrid_astar_planner { +//类插件实现的多态的时候,若在头文件中定义了函数,那么就必须有这个函数的实现,否则会报错!!! +/** + * @class HybridAStarPlanner + * @brief Provides a ROS wrapper for the HybridAStarPlanner planner which runs a fast, interpolated navigation function on a costmap. + */ + +class HybridAStarPlanner : public nav_core::BaseGlobalPlanner { + public: + /** + * @brief Default constructor for the HybridAStarPlanner object + */ + HybridAStarPlanner(); + + /** + * @brief Default deconstructor for the HybridAStarPlanner object + */ + ~HybridAStarPlanner(); + + /** + * @brief Initialization function for the HybridAStarPlanner + * @param name The name of this planner + * @param costmap_ros A pointer to the ROS wrapper of the costmap to use for planning.And the costmap is get from the topic name /map + */ + void initialize(std::string name, costmap_2d::Costmap2DROS* costmap_ros); + + void initialize(std::string name, costmap_2d::Costmap2D* costmap, std::string frame_id); + + /** + * @brief Given a goal pose in the world, compute a plan + * @param start The start pose + * @param goal The goal pose + * @param plan The plan... filled by the planner + * @return True if a valid plan was found, false otherwise + */ + bool makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, + std::vector& plan); + + /** + * @brief Publish the plan to RVIZ + * @param path the vector contain the path + */ + void publishPlan(const std::vector& path); + + /** + * @brief Publish the path node to RVIZ + * @param path the vector contain the path + */ + void publishPathNodes(const std::vector& path); + + /** + * @brief The call back function of makeplan service + * @param req + * @param resp the plan the planner made + * @return True if a valid plan was found, false otherwise + */ + bool makePlanService(nav_msgs::GetPlan::Request& req, nav_msgs::GetPlan::Response& resp); + protected: + + bool initialized_; + std::string frame_id_; + ros::Publisher plan_pub_; + ros::Publisher path_vehicles_pub_;//用于在路径上发布车子位置 + costmap_2d::Costmap2D* costmap; + + private: + /** + * @brief Clarn the visualization_msgs::Marker 清理可视化信息的标记点 + */ + void clearPathNodes(void); + + + + /** + * @brief Check whethe the start pose is available + * @param start A reference to start pose + * @return True if the start pose is available + */ + bool checkStartPose(const geometry_msgs::PoseStamped &start); + + /** + * @brief Check whethe the goal pose is available + * @param goal A reference to goal pose + * @return True if the goal pose is available + */ + bool checkgoalPose(const geometry_msgs::PoseStamped &goal); + visualization_msgs::MarkerArray pathNodes;//节点数据结构,用于可视化 + double resolution; + ros::ServiceServer make_plan_srv_; + bool use_hybrid_astar; + +}; + + +} //end namespace hybrid_astar_planner + +#endif diff --git a/Src/hybrid_astar_planner-main/include/visualize.h b/Src/hybrid_astar_planner-main/include/visualize.h new file mode 100644 index 00000000..56b8daf9 --- /dev/null +++ b/Src/hybrid_astar_planner-main/include/visualize.h @@ -0,0 +1,10 @@ +#ifndef _VISUALIZE_H +#define _VISUALIZE_H +#include "node3d.h" +#include +#include +namespace hybrid_astar_planner { + void publishSearchNodes(Node3D node,ros::Publisher& pub, visualization_msgs::MarkerArray& pathNodes, int i); +} + +#endif//end of visualize,h \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/package.xml b/Src/hybrid_astar_planner-main/package.xml new file mode 100644 index 00000000..d317c120 --- /dev/null +++ b/Src/hybrid_astar_planner-main/package.xml @@ -0,0 +1,49 @@ + + + hybrid_astar_planner + 1.1.2 + A hybrid_astar_planner package for move_base + dengpw + + + + + + BSD + + + + + + + catkin + pluginlib + pluginlib + pluginlib + + + nav_core + roscpp + rospy + std_msgs + visualization_msgs + tf + ompl + map_server + + nav_core + roscpp + rospy + std_msgs + visualization_msgs + tf + ompl + map_server + + + + + + + + diff --git a/Src/hybrid_astar_planner-main/src/ReedsShepp.cpp b/Src/hybrid_astar_planner-main/src/ReedsShepp.cpp new file mode 100644 index 00000000..6234d541 --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/ReedsShepp.cpp @@ -0,0 +1,623 @@ +/********************************************************************* +* +* Software License Agreement (BSD License) +* +* Copyright (c) 2016, Guan-Horng Liu. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* Author: Guan-Horng Liu +*********************************************************************/ + + +#include "ReedsShepp.h" +#include + + +namespace +{ + // The comments, variable names, etc. use the nomenclature from the Reeds & Shepp paper. + + const double pi = boost::math::constants::pi(); + const double twopi = 2. * pi; + const double RS_EPS = 1e-6; + const double ZERO = 10*std::numeric_limits::epsilon(); + + inline double mod2pi(double x) + { + double v = fmod(x, twopi); + if (v < -pi) + v += twopi; + else + if (v > pi) + v -= twopi; + return v; + } + inline void polar(double x, double y, double &r, double &theta) + { + r = sqrt(x*x + y*y); + theta = atan2(y, x); + } + inline void tauOmega(double u, double v, double xi, double eta, double phi, double &tau, double &omega) + { + double delta = mod2pi(u-v), A = sin(u) - sin(delta), B = cos(u) - cos(delta) - 1.; + double t1 = atan2(eta*A - xi*B, xi*A + eta*B), t2 = 2. * (cos(delta) - cos(v) - cos(u)) + 3; + tau = (t2<0) ? mod2pi(t1+pi) : mod2pi(t1); + omega = mod2pi(tau - u + v - phi) ; + } + + // formula 8.1 in Reeds-Shepp paper + inline bool LpSpLp(double x, double y, double phi, double &t, double &u, double &v) + { + polar(x - sin(phi), y - 1. + cos(phi), u, t); + if (t >= -ZERO) + { + v = mod2pi(phi - t); + if (v >= -ZERO) + { + assert(fabs(u*cos(t) + sin(phi) - x) < RS_EPS); + assert(fabs(u*sin(t) - cos(phi) + 1 - y) < RS_EPS); + assert(fabs(mod2pi(t+v - phi)) < RS_EPS); + return true; + } + } + return false; + } + // formula 8.2 + inline bool LpSpRp(double x, double y, double phi, double &t, double &u, double &v) + { + double t1, u1; + polar(x + sin(phi), y - 1. - cos(phi), u1, t1); + u1 = u1*u1; + if (u1 >= 4.) + { + double theta; + u = sqrt(u1 - 4.); + theta = atan2(2., u); + t = mod2pi(t1 + theta); + v = mod2pi(t - phi); + assert(fabs(2*sin(t) + u*cos(t) - sin(phi) - x) < RS_EPS); + assert(fabs(-2*cos(t) + u*sin(t) + cos(phi) + 1 - y) < RS_EPS); + assert(fabs(mod2pi(t-v - phi)) < RS_EPS); + return t>=-ZERO && v>=-ZERO; + } + return false; + } + void CSC(double x, double y, double phi, ReedsSheppStateSpace::ReedsSheppPath &path) + { + double t, u, v, Lmin = path.length(), L; + if (LpSpLp(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[14], t, u, v); + Lmin = L; + } + if (LpSpLp(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[14], -t, -u, -v); + Lmin = L; + } + if (LpSpLp(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[15], t, u, v); + Lmin = L; + } + if (LpSpLp(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[15], -t, -u, -v); + Lmin = L; + } + + if (LpSpRp(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[12], t, u, v); + Lmin = L; + } + if (LpSpRp(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[12], -t, -u, -v); + Lmin = L; + } + if (LpSpRp(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[13], t, u, v); + Lmin = L; + } + if (LpSpRp(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[13], -t, -u, -v); + } + // formula 8.3 / 8.4 *** TYPO IN PAPER *** + inline bool LpRmL(double x, double y, double phi, double &t, double &u, double &v) + { + double xi = x - sin(phi), eta = y - 1. + cos(phi), u1, theta; + polar(xi, eta, u1, theta); + if (u1 <= 4.) + { + u = -2.*asin(.25 * u1); + t = mod2pi(theta + .5 * u + pi); + v = mod2pi(phi - t + u); + assert(fabs(2*(sin(t) - sin(t-u)) + sin(phi) - x) < RS_EPS); + assert(fabs(2*(-cos(t) + cos(t-u)) - cos(phi) + 1 - y) < RS_EPS); + assert(fabs(mod2pi(t-u+v - phi)) < RS_EPS); + return t>=-ZERO && u<=ZERO; + } + return false; + } + void CCC(double x, double y, double phi, ReedsSheppStateSpace::ReedsSheppPath &path) + { + double t, u, v, Lmin = path.length(), L; + if (LpRmL(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[0], t, u, v); + Lmin = L; + } + if (LpRmL(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[0], -t, -u, -v); + Lmin = L; + } + if (LpRmL(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[1], t, u, v); + Lmin = L; + } + if (LpRmL(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[1], -t, -u, -v); + Lmin = L; + } + + // backwards + double xb = x*cos(phi) + y*sin(phi), yb = x*sin(phi) - y*cos(phi); + if (LpRmL(xb, yb, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[0], v, u, t); + Lmin = L; + } + if (LpRmL(-xb, yb, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[0], -v, -u, -t); + Lmin = L; + } + if (LpRmL(xb, -yb, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[1], v, u, t); + Lmin = L; + } + if (LpRmL(-xb, -yb, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[1], -v, -u, -t); + } + // formula 8.7 + inline bool LpRupLumRm(double x, double y, double phi, double &t, double &u, double &v) + { + double xi = x + sin(phi), eta = y - 1. - cos(phi), rho = .25 * (2. + sqrt(xi*xi + eta*eta)); + if (rho <= 1.) + { + u = acos(rho); + tauOmega(u, -u, xi, eta, phi, t, v); + assert(fabs(2*(sin(t)-sin(t-u)+sin(t-2*u))-sin(phi) - x) < RS_EPS); + assert(fabs(2*(-cos(t)+cos(t-u)-cos(t-2*u))+cos(phi)+1 - y) < RS_EPS); + assert(fabs(mod2pi(t-2*u-v - phi)) < RS_EPS); + return t>=-ZERO && v<=ZERO; + } + return false; + } + // formula 8.8 + inline bool LpRumLumRp(double x, double y, double phi, double &t, double &u, double &v) + { + double xi = x + sin(phi), eta = y - 1. - cos(phi), rho = (20. - xi*xi - eta*eta) / 16.; + if (rho>=0 && rho<=1) + { + u = -acos(rho); + if (u >= -.5 * pi) + { + tauOmega(u, u, xi, eta, phi, t, v); + assert(fabs(4*sin(t)-2*sin(t-u)-sin(phi) - x) < RS_EPS); + assert(fabs(-4*cos(t)+2*cos(t-u)+cos(phi)+1 - y) < RS_EPS); + assert(fabs(mod2pi(t-v - phi)) < RS_EPS); + return t>=-ZERO && v>=-ZERO; + } + } + return false; + } + void CCCC(double x, double y, double phi, ReedsSheppStateSpace::ReedsSheppPath &path) + { + double t, u, v, Lmin = path.length(), L; + if (LpRupLumRm(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[2], t, u, -u, v); + Lmin = L; + } + if (LpRupLumRm(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[2], -t, -u, u, -v); + Lmin = L; + } + if (LpRupLumRm(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[3], t, u, -u, v); + Lmin = L; + } + if (LpRupLumRm(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) // timeflip + reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[3], -t, -u, u, -v); + Lmin = L; + } + + if (LpRumLumRp(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[2], t, u, u, v); + Lmin = L; + } + if (LpRumLumRp(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[2], -t, -u, -u, -v); + Lmin = L; + } + if (LpRumLumRp(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[3], t, u, u, v); + Lmin = L; + } + if (LpRumLumRp(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + 2.*fabs(u) + fabs(v))) // timeflip + reflect + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[3], -t, -u, -u, -v); + } + // formula 8.9 + inline bool LpRmSmLm(double x, double y, double phi, double &t, double &u, double &v) + { + double xi = x - sin(phi), eta = y - 1. + cos(phi), rho, theta; + polar(xi, eta, rho, theta); + if (rho >= 2.) + { + double r = sqrt(rho*rho - 4.); + u = 2. - r; + t = mod2pi(theta + atan2(r, -2.)); + v = mod2pi(phi - .5*pi - t); + assert(fabs(2*(sin(t)-cos(t))-u*sin(t)+sin(phi) - x) < RS_EPS); + assert(fabs(-2*(sin(t)+cos(t))+u*cos(t)-cos(phi)+1 - y) < RS_EPS); + assert(fabs(mod2pi(t+pi/2+v-phi)) < RS_EPS); + return t>=-ZERO && u<=ZERO && v<=ZERO; + } + return false; + } + // formula 8.10 + inline bool LpRmSmRm(double x, double y, double phi, double &t, double &u, double &v) + { + double xi = x + sin(phi), eta = y - 1. - cos(phi), rho, theta; + polar(-eta, xi, rho, theta); + if (rho >= 2.) + { + t = theta; + u = 2. - rho; + v = mod2pi(t + .5*pi - phi); + assert(fabs(2*sin(t)-cos(t-v)-u*sin(t) - x) < RS_EPS); + assert(fabs(-2*cos(t)-sin(t-v)+u*cos(t)+1 - y) < RS_EPS); + assert(fabs(mod2pi(t+pi/2-v-phi)) < RS_EPS); + return t>=-ZERO && u<=ZERO && v<=ZERO; + } + return false; + } + void CCSC(double x, double y, double phi, ReedsSheppStateSpace::ReedsSheppPath &path) + { + double t, u, v, Lmin = path.length() - .5*pi, L; + if (LpRmSmLm(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[4], t, -.5*pi, u, v); + Lmin = L; + } + if (LpRmSmLm(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[4], -t, .5*pi, -u, -v); + Lmin = L; + } + if (LpRmSmLm(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[5], t, -.5*pi, u, v); + Lmin = L; + } + if (LpRmSmLm(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[5], -t, .5*pi, -u, -v); + Lmin = L; + } + + if (LpRmSmRm(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[8], t, -.5*pi, u, v); + Lmin = L; + } + if (LpRmSmRm(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[8], -t, .5*pi, -u, -v); + Lmin = L; + } + if (LpRmSmRm(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[9], t, -.5*pi, u, v); + Lmin = L; + } + if (LpRmSmRm(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[9], -t, .5*pi, -u, -v); + Lmin = L; + } + + // backwards + double xb = x*cos(phi) + y*sin(phi), yb = x*sin(phi) - y*cos(phi); + if (LpRmSmLm(xb, yb, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[6], v, u, -.5*pi, t); + Lmin = L; + } + if (LpRmSmLm(-xb, yb, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[6], -v, -u, .5*pi, -t); + Lmin = L; + } + if (LpRmSmLm(xb, -yb, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[7], v, u, -.5*pi, t); + Lmin = L; + } + if (LpRmSmLm(-xb, -yb, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[7], -v, -u, .5*pi, -t); + Lmin = L; + } + + if (LpRmSmRm(xb, yb, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[10], v, u, -.5*pi, t); + Lmin = L; + } + if (LpRmSmRm(-xb, yb, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[10], -v, -u, .5*pi, -t); + Lmin = L; + } + if (LpRmSmRm(xb, -yb, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[11], v, u, -.5*pi, t); + Lmin = L; + } + if (LpRmSmRm(-xb, -yb, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[11], -v, -u, .5*pi, -t); + } + // formula 8.11 *** TYPO IN PAPER *** + inline bool LpRmSLmRp(double x, double y, double phi, double &t, double &u, double &v) + { + double xi = x + sin(phi), eta = y - 1. - cos(phi), rho, theta; + polar(xi, eta, rho, theta); + if (rho >= 2.) + { + u = 4. - sqrt(rho*rho - 4.); + if (u <= ZERO) + { + t = mod2pi(atan2((4-u)*xi -2*eta, -2*xi + (u-4)*eta)); + v = mod2pi(t - phi); + assert(fabs(4*sin(t)-2*cos(t)-u*sin(t)-sin(phi) - x) < RS_EPS); + assert(fabs(-4*cos(t)-2*sin(t)+u*cos(t)+cos(phi)+1 - y) < RS_EPS); + assert(fabs(mod2pi(t-v-phi)) < RS_EPS); + return t>=-ZERO && v>=-ZERO; + } + } + return false; + } + void CCSCC(double x, double y, double phi, ReedsSheppStateSpace::ReedsSheppPath &path) + { + double t, u, v, Lmin = path.length() - pi, L; + if (LpRmSLmRp(x, y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[16], t, -.5*pi, u, -.5*pi, v); + Lmin = L; + } + if (LpRmSLmRp(-x, y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[16], -t, .5*pi, -u, .5*pi, -v); + Lmin = L; + } + if (LpRmSLmRp(x, -y, -phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // reflect + { + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[17], t, -.5*pi, u, -.5*pi, v); + Lmin = L; + } + if (LpRmSLmRp(-x, -y, phi, t, u, v) && Lmin > (L = fabs(t) + fabs(u) + fabs(v))) // timeflip + reflect + path = ReedsSheppStateSpace::ReedsSheppPath( + ReedsSheppStateSpace::reedsSheppPathType[17], -t, .5*pi, -u, .5*pi, -v); + } + + ReedsSheppStateSpace::ReedsSheppPath reedsShepp(double x, double y, double phi) + { + ReedsSheppStateSpace::ReedsSheppPath path; + CSC(x, y, phi, path); + CCC(x, y, phi, path); + CCCC(x, y, phi, path); + CCSC(x, y, phi, path); + CCSCC(x, y, phi, path); + return path; + } +} + +const ReedsSheppStateSpace::ReedsSheppPathSegmentType +ReedsSheppStateSpace::reedsSheppPathType[18][5] = { + { RS_LEFT, RS_RIGHT, RS_LEFT, RS_NOP, RS_NOP }, // 0 + { RS_RIGHT, RS_LEFT, RS_RIGHT, RS_NOP, RS_NOP }, // 1 + { RS_LEFT, RS_RIGHT, RS_LEFT, RS_RIGHT, RS_NOP }, // 2 + { RS_RIGHT, RS_LEFT, RS_RIGHT, RS_LEFT, RS_NOP }, // 3 + { RS_LEFT, RS_RIGHT, RS_STRAIGHT, RS_LEFT, RS_NOP }, // 4 + { RS_RIGHT, RS_LEFT, RS_STRAIGHT, RS_RIGHT, RS_NOP }, // 5 + { RS_LEFT, RS_STRAIGHT, RS_RIGHT, RS_LEFT, RS_NOP }, // 6 + { RS_RIGHT, RS_STRAIGHT, RS_LEFT, RS_RIGHT, RS_NOP }, // 7 + { RS_LEFT, RS_RIGHT, RS_STRAIGHT, RS_RIGHT, RS_NOP }, // 8 + { RS_RIGHT, RS_LEFT, RS_STRAIGHT, RS_LEFT, RS_NOP }, // 9 + { RS_RIGHT, RS_STRAIGHT, RS_RIGHT, RS_LEFT, RS_NOP }, // 10 + { RS_LEFT, RS_STRAIGHT, RS_LEFT, RS_RIGHT, RS_NOP }, // 11 + { RS_LEFT, RS_STRAIGHT, RS_RIGHT, RS_NOP, RS_NOP }, // 12 + { RS_RIGHT, RS_STRAIGHT, RS_LEFT, RS_NOP, RS_NOP }, // 13 + { RS_LEFT, RS_STRAIGHT, RS_LEFT, RS_NOP, RS_NOP }, // 14 + { RS_RIGHT, RS_STRAIGHT, RS_RIGHT, RS_NOP, RS_NOP }, // 15 + { RS_LEFT, RS_RIGHT, RS_STRAIGHT, RS_LEFT, RS_RIGHT }, // 16 + { RS_RIGHT, RS_LEFT, RS_STRAIGHT, RS_RIGHT, RS_LEFT } // 17 +}; + +ReedsSheppStateSpace::ReedsSheppPath::ReedsSheppPath(const ReedsSheppPathSegmentType* type, + double t, double u, double v, double w, double x) + : type_(type) +{ + length_[0] = t; length_[1] = u; length_[2] = v; length_[3] = w; length_[4] = x; + totalLength_ = fabs(t) + fabs(u) + fabs(v) + fabs(w) + fabs(x); +} + + +double ReedsSheppStateSpace::distance(double q0[3], double q1[3]) +{ + return rho_ * reedsShepp(q0, q1).length(); +} + +ReedsSheppStateSpace::ReedsSheppPath ReedsSheppStateSpace::reedsShepp(double q0[3], double q1[3]) +{ + double dx = q1[0] - q0[0], dy = q1[1] - q0[1], dth = q1[2] - q0[2]; + double c = cos(q0[2]), s = sin(q0[2]); + double x = c*dx + s*dy, y = -s*dx + c*dy; + return ::reedsShepp(x/rho_, y/rho_, dth); +} + +std::vector ReedsSheppStateSpace::type(double q0[3], double q1[3]) +{ + ReedsSheppPath path = reedsShepp(q0, q1); + std::vector type_list; + for (int i=0;i<5;++i) + type_list.push_back(path.type_[i]); + return type_list; +} + +void ReedsSheppStateSpace::sample(double q0[3], double q1[3], double step_size, double &length, std::vector > &points) +{ + ReedsSheppPath path = reedsShepp(q0, q1); + length = rho_ * path.length(); + + for (double seg=0.0; seg<=length; seg+=step_size) { + double qnew[3] = {}; + interpolate(q0, path, seg/rho_, qnew); + std::vector v(qnew, qnew + sizeof qnew / sizeof qnew[0]); + points.push_back(v); + } + return; +} + +void ReedsSheppStateSpace::interpolate(double q0[3], ReedsSheppPath &path, double seg, double s[3]) +{ + + if (seg < 0.0) seg = 0.0; + if (seg > path.length()) seg = path.length(); + + double phi, v; + + s[0] = s[1] = 0.0; + s[2] = q0[2]; + + for (unsigned int i=0; i<5 && seg>0; ++i) + { + if (path.length_[i]<0) + { + v = std::max(-seg, path.length_[i]); + seg += v; + } + else + { + v = std::min(seg, path.length_[i]); + seg -= v; + } + phi = s[2]; + switch(path.type_[i]) + { + case RS_LEFT: + s[0] += ( sin(phi+v) - sin(phi)); + s[1] += (-cos(phi+v) + cos(phi)); + s[2] = phi + v; + break; + case RS_RIGHT: + s[0] += (-sin(phi-v) + sin(phi)); + s[1] += ( cos(phi-v) - cos(phi)); + s[2] = phi - v; + break; + case RS_STRAIGHT: + s[0] += (v * cos(phi)); + s[1] += (v * sin(phi)); + break; + case RS_NOP: + break; + } + } + + s[0] = s[0] * rho_ + q0[0]; + s[1] = s[1] * rho_ + q0[1]; +} diff --git a/Src/hybrid_astar_planner-main/src/a_start.cpp b/Src/hybrid_astar_planner-main/src/a_start.cpp new file mode 100644 index 00000000..b1c585dd --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/a_start.cpp @@ -0,0 +1,147 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + *********************************************************************/ +#include "node2d.h" +#include "astar.h" +#include +namespace hybrid_astar_planner { + +bool astar::calculatePath(const geometry_msgs::PoseStamped& start, + const geometry_msgs::PoseStamped& goal, + int cells_x, int cells_y, std::vector& plan, + ros::Publisher& pub, visualization_msgs::MarkerArray& pathNodes ) { + + const unsigned char* charMap = costmap->getCharMap(); + + int counter = 0; // 记录程序搜寻节点次数 + float resolution = costmap->getResolution();// 获取代价图的分辨率 + + // 使用boost库中的二项堆,优化优先队列的性能 + boost::heap::binomial_heap> openSet; + unsigned int startx, starty, goalx, goaly; + // 坐标转换,将世界坐标转换为costmap使用的绝对坐标 + costmap->worldToMap(start.pose.position.x, start.pose.position.y, startx, starty); + costmap->worldToMap(goal.pose.position.x, goal.pose.position.y, goalx, goaly); + Node2D* pathNode2D = new Node2D[cells_x * cells_y](); // 与代价图等大的2Dnode栅格节点 + + // 设置开始节点与结束节点指针,指针指向其对应2D节点图中的点位 + Node2D* startPose = &pathNode2D[ startx * cells_y + starty ]; + Node2D* goalPose = &pathNode2D[ goalx * cells_y + goaly ]; + + // 设置起始节点和结束节点的坐标,以便后续进行比较计算 + goalPose->setX( goalx ); + goalPose->setY( goaly ); + startPose->setX( startx ); + startPose->setY( starty ); + startPose->setG(0); + openSet.push( startPose ); + startPose->setOpenSet(); + + Node2D* tmpStart; + while(openSet.size()) { + ++counter; + tmpStart = openSet.top(); + openSet.pop(); + //如果找到目标点则返回 + if(tmpStart->getX() == goalPose->getX() && tmpStart->getY() == goalPose->getY() ) { + std::cout << "got a plan" << std::endl; + nodeToPlan(tmpStart, plan); + std::cout << counter << std::endl; + delete [] pathNode2D; + return true; + } + std::vector adjacentNodes = gatAdjacentPoints(cells_x, cells_y, charMap, pathNode2D, tmpStart ); + tmpStart->setClosedSet(); + + //下面正式开始A*算法的核心搜索部分 + for (std::vector::iterator it = adjacentNodes.begin(); it != adjacentNodes.end(); ++it) { + Node2D* point = *it; + float g; + if (!point->isClosedSet()) { + g = point->calcG(tmpStart); + // 在此拓展点为初次被探索时,设置此点的G值,设置其父节点。或是以其他路径到达此点的G值更小时,重新设置此点的父节点 + if (!point->isOpenSet() || (g < point->getG())) { + point->setPerd(tmpStart); + point->setG(g); + if(!point->isOpenSet()) { + point->calcH(goalPose); // 计算此点距离目标节点距离(作为启发值) + point->setOpenSet(); // 将此拓展点加入开集合中 + } + openSet.push(point); + } + } + } + } + + delete [] pathNode2D; //删除产生的Node2D节点 + return false; //搜索失败 +} + +std::vector astar::gatAdjacentPoints(int cells_x, int cells_y, const unsigned char* charMap, Node2D* pathNode2D, Node2D *point ) { + std::vector adjacentNodes; + for (int x = point->getX() - 1; x <= point->getX() + 1; ++x) { + for (int y = point->getY() - 1; y <= point->getY() + 1; ++y) { + if (charMap[x + y* cells_x] <= 1) { + pathNode2D[x * cells_y + y].setX(x); + pathNode2D[x * cells_y + y].setY(y); + adjacentNodes.push_back(&pathNode2D[x * cells_y + y]); + } + } + }//end of for + + return adjacentNodes; +} + +void astar::nodeToPlan(Node2D* node, std::vector& plan) { + Node2D* tmpPtr = node; + geometry_msgs::PoseStamped tmpPose; + tmpPose.header.stamp = ros::Time::now(); + //参数后期处理,发布到RViz上进行可视化 + tmpPose.pose.orientation = tf::createQuaternionMsgFromYaw(0); + std::vector replan; + while(tmpPtr!=nullptr) { + costmap->mapToWorld(tmpPtr->getX(), tmpPtr->getY(), tmpPose.pose.position.x, tmpPose.pose.position.y); + tmpPose.header.frame_id = frame_id_; + replan.push_back(tmpPose); + tmpPtr = tmpPtr->getPerd(); + } + int size = replan.size(); + for (int i = 0;i < size; ++i) { + plan.push_back(replan[size - i -1 ]); + } +} + +}// namespace hybrid_astar_planner diff --git a/Src/hybrid_astar_planner-main/src/algorithm.cpp b/Src/hybrid_astar_planner-main/src/algorithm.cpp new file mode 100644 index 00000000..3484df68 --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/algorithm.cpp @@ -0,0 +1,201 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + *********************************************************************/ +#include "algorithm.h" +#include "dubins.h" +#include "ReedsShepp.h" +#include +#include +// #include +// #include +namespace hybrid_astar_planner { + +std::vector gatAdjacentPoints(int cells_x, int cells_y, const unsigned char* charMap, Node2D* pathNode2D, Node2D *point ) { + std::vector adjacentNodes; + for (int x = point->getX() - 1; x <= point->getX() + 1; ++x) { + for (int y = point->getY() - 1; y <= point->getY() + 1; ++y) { + if (charMap[x + y* cells_x] < 253) { + pathNode2D[x * cells_y + y].setX(x); + pathNode2D[x * cells_y + y].setY(y); + pathNode2D[x * cells_y + y].setCost(charMap[x + y* cells_x]); + adjacentNodes.push_back(&pathNode2D[x * cells_y + y]); + } + } + }//end of for + + return adjacentNodes; +} +void nodeToPlan(Node2D* node, std::vector& plan, costmap_2d::Costmap2D* costmap, std::string frame_id_) { + Node2D* tmpPtr = node; + geometry_msgs::PoseStamped tmpPose; + tmpPose.header.stamp = ros::Time::now(); + //参数后期处理,发布到RViz上进行可视化 + tmpPose.pose.orientation = tf::createQuaternionMsgFromYaw(0); + std::vector replan; + while(tmpPtr!=nullptr) { + costmap->mapToWorld(tmpPtr->getX(), tmpPtr->getY(), tmpPose.pose.position.x, tmpPose.pose.position.y); + tmpPose.header.frame_id = frame_id_; + replan.push_back(tmpPose); + tmpPtr = tmpPtr->getPerd(); + } + int size = replan.size(); + for (int i = 0;i < size; ++i) { + plan.push_back(replan[size - i -1 ]); + } +} + +void updateH(Node3D& start, const Node3D& goal, Node2D* nodes2D, + float* dubinsLookup, int width, int height, float inspireAstar) { + float reedsSheppCost = 0; + float twoDCost = 0; + float twoDoffset = 0; + #ifdef use_ReedsShepp_heuristic + // 假如车子可以后退,则可以启动Reeds-Shepp 算法 + if (Constants::reverse && !Constants::dubins) { + //reeds_shepp算法还还存在问题,启用可能会造成搜寻路径增加等问题 + + ompl::base::ReedsSheppStateSpace reedsSheppPath(Constants::r); + State* rsStart = (State*)reedsSheppPath.allocState(); + State* rsEnd = (State*)reedsSheppPath.allocState(); + rsStart->setXY(start.getX(), start.getY()); + rsStart->setYaw(start.getT()); + rsEnd->setXY(goal.getX(), goal.getY()); + rsEnd->setYaw(goal.getT()); + reedsSheppCost = reedsSheppPath.distance(rsStart, rsEnd) * 1.1 + + 0.04 * start.getCost(); + + } + #endif + start.setH(std::max(reedsSheppCost, inspireAstar));//将两个代价中的最大值作为启发式值 +} + + +Node3D* dubinsShot(Node3D& start, Node3D& goal, costmap_2d::Costmap2D* costmap) { + // start + double q0[] = { start.getX(), start.getY(), start.getT() }; + // goal + double q1[] = { goal.getX(), goal.getY(), goal.getT() }; + // initialize the path + DubinsPath path; + // calculate the path + dubins_init(q0, q1, Constants::r, &path); + + unsigned int poseX, poseY; + + int i = 0; + float x = 0.f; + float length = dubins_path_length(&path); + // printf("the length of dubins %f",length); + Node3D* dubinsNodes = new Node3D [(int)(length / Constants::dubinsStepSize) + 1]; + + while (x < length) {//这是跳出循环的条件之一:生成的路径没有达到所需要的长度 + double q[3]; + dubins_path_sample(&path, x, q); + dubinsNodes[i].setX(q[0]); + dubinsNodes[i].setY(q[1]); + dubinsNodes[i].setT(q[2]); + + // collision check + //跳出循环的条件之二:生成的路径存在碰撞节点 + costmap->worldToMap(dubinsNodes[i].getX(), dubinsNodes[i].getY(), poseX, poseY); + if (costmap->getCost(poseX, poseY) <= 1) { + + // set the predecessor to the previous step + if (i > 0) { + dubinsNodes[i].setPerd(&dubinsNodes[i - 1]); + } else { + dubinsNodes[i].setPerd(&start); + } + + if (&dubinsNodes[i] == dubinsNodes[i].getPerd()) { + std::cout << "looping shot"; + } + + x += Constants::dubinsStepSize; + i++; + } else { + delete [] dubinsNodes; + return nullptr; + } + } + //返回末节点,通过getPred()可以找到前一节点。 + return &dubinsNodes[i - 1]; +} + +Node3D* reedsSheppShot(Node3D& start, Node3D& goal, costmap_2d::Costmap2D* costmap) { + + ReedsSheppStateSpace rs_planner(Constants::r); + double length = -1; + unsigned int poseX, poseY; + // start + double q0[] = { start.getX(), start.getY(), start.getT() }; + // goal + double q1[] = { goal.getX(), goal.getY(), goal.getT() }; + std::vector > rs_path; + rs_planner.sample(q0, q1, Constants::dubinsStepSize, length, rs_path); + Node3D* dubinsNodes = new Node3D [(int)(length / Constants::dubinsStepSize) + 1]; + int i = 0; + dubinsNodes[1].setPerd(&start); + for (auto &point_itr : rs_path) { + dubinsNodes[i].setX(point_itr[0]); + dubinsNodes[i].setY(point_itr[1]); + dubinsNodes[i].setT(point_itr[2]); + + //collision check + costmap->worldToMap(dubinsNodes[i].getX(), dubinsNodes[i].getY(), poseX, poseY); + if (costmap->getCost(poseX, poseY) < 100) { + // set the predecessor to the previous step + if (i > 1) { + dubinsNodes[i].setPerd(&dubinsNodes[i - 1]); + } + // else { + // dubinsNodes[i].setPerd(&start); + // } + if (&dubinsNodes[i] == dubinsNodes[i].getPerd()) { + std::cout << "looping shot"; + } + i++; + } else { + delete [] dubinsNodes; + return nullptr; + } + } + //返回末节点,通过getPred()可以找到前一节点。 + return &dubinsNodes[i - 1]; + +} + +} //namespace hybrid_astar_planner \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/src/dubins.cpp b/Src/hybrid_astar_planner-main/src/dubins.cpp new file mode 100644 index 00000000..c473ab92 --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/dubins.cpp @@ -0,0 +1,448 @@ +// Copyright (c) 2008-2014, Andrew Walker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef DUBINS_CPP +#define DUBINS_CPP + +#include "dubins.h" +#define _USE_MATH_DEFINES // for C++ +#include +#include + +#define EPSILON (10e-10) + +#define LSL (0) +#define LSR (1) +#define RSL (2) +#define RSR (3) +#define RLR (4) +#define LRL (5) + +// The three segment types a path can be made up of +#define L_SEG (0) +#define S_SEG (1) +#define R_SEG (2) + +namespace hybrid_astar_planner{ + +// The segment types for each of the Path types +const int DIRDATA[][3] = { + { L_SEG, S_SEG, L_SEG }, + { L_SEG, S_SEG, R_SEG }, + { R_SEG, S_SEG, L_SEG }, + { R_SEG, S_SEG, R_SEG }, + { R_SEG, L_SEG, R_SEG }, + { L_SEG, R_SEG, L_SEG } +}; + +//函数指针数组,可以指向不同的函数 +//原型为 typedef int (*DubinsWord)(double, double, double, double* ); +DubinsWord dubins_words[] = { + dubins_LSL, + dubins_LSR, + dubins_RSL, + dubins_RSR, + dubins_RLR, + dubins_LRL, +}; + +//这里定义宏展开,方便简化代码 +#define UNPACK_INPUTS(alpha, beta) \ + double sa = sin(alpha); \ + double sb = sin(beta); \ + double ca = cos(alpha); \ + double cb = cos(beta); \ + double c_ab = cos(alpha - beta); \ + +//定义宏展开,方便简化代码 +#define PACK_OUTPUTS(outputs) \ + outputs[0] = t; \ + outputs[1] = p; \ + outputs[2] = q; + +/** + * Floating point modulus suitable for rings + * + * fmod doesn't behave correctly for angular quantities, this function does + */ +/** + * 两浮点数取模 + */ +double fmodr( double x, double y) +{ + return x - y*floor(x/y); +} + +/** + * @brief 将角度范围限制在(-2pi, 2*pi)之间 + * + * @param theta 角度 + * @return double 计算结果 + */ +double mod2pi( double theta ) +{ + return fmodr( theta, 2 * M_PI ); +} + +/** + * @brief 根据alpha, beta, d三个参数找出Dubins类型(LSL, LSR, RSL, RSR, RLR or LRL) + * 并将每段曲线的线段长度(代价)存放到path->param和path->type中 + * 注:这是一种简单的穷举尝试策略,与文章“Classification of the Dubins set”描述的策略不同。 + * + * @param alpha :角度参数,表示起点朝向 + * @param beta :角度参数,表示终点朝向 + * @param d :起点和终点的距离 + * @param path 存放结果,用到两个: path->param和path->type + * @return int 返回值:非0值表示出错;0表示正常 + */ +int dubins_init_normalised( double alpha, double beta, double d, DubinsPath* path) +{ + double best_cost = INFINITY; + int best_word; + int i; + + best_word = -1; + for( i = 0; i < 6; i++ ) { + double params[3]; + //分别调用不同的Dubins函数曲线计算得到t,p, q,存放于params + int err = dubins_words[i](alpha, beta, d, params); + if(err == EDUBOK) { + double cost = params[0] + params[1] + params[2];//三段线段的长度作为代价 + if(cost < best_cost) {//将最好的结果保存到path->param看 + best_word = i; + best_cost = cost; + path->param[0] = params[0]; + path->param[1] = params[1]; + path->param[2] = params[2]; + path->type = i; + } + } + } + + if(best_word == -1) { + return EDUBNOPATH; + } + path->type = best_word; + return EDUBOK; +} + +/** + * @brief 依据始点、末点位置和最小转弯半径生成一条Dubin PATH + * + * @param q0 始点 + * @param q1 末点 + * @param rho 最小转弯半径 + * @param path 生成的路径 + * @return int + */ +int dubins_init( double q0[3], double q1[3], double rho, DubinsPath* path ) +{ + int i; + double dx = q1[0] - q0[0]; + double dy = q1[1] - q0[1]; + double D = sqrt( dx * dx + dy * dy ); + double d = D / rho;//将两点距离除以最小转弯半径得到归一化距离d + if( rho <= 0. ) { + return EDUBBADRHO; + } + double theta = mod2pi(atan2( dy, dx )); + double alpha = mod2pi(q0[2] - theta); + double beta = mod2pi(q1[2] - theta);//计算坐标原点移到第一个点后,始点和终点的朝向 + for( i = 0; i < 3; i ++ ) {//将起点放入path->qi变量 + path->qi[i] = q0[i]; + } + path->rho = rho;//最小转弯半径 + + return dubins_init_normalised( alpha, beta, d, path ); +} + +int dubins_LSL( double alpha, double beta, double d, double* outputs ) +{ + UNPACK_INPUTS(alpha, beta); + double tmp0 = d+sa-sb; + double p_squared = 2 + (d*d) -(2*c_ab) + (2*d*(sa - sb)); + if( p_squared < 0 ) { + return EDUBNOPATH; + } + double tmp1 = atan2( (cb-ca), tmp0 ); + double t = mod2pi(-alpha + tmp1 ); + double p = sqrt( p_squared ); + double q = mod2pi(beta - tmp1 ); + PACK_OUTPUTS(outputs); + return EDUBOK; +} + +int dubins_RSR( double alpha, double beta, double d, double* outputs ) +{ + UNPACK_INPUTS(alpha, beta); + double tmp0 = d-sa+sb; + double p_squared = 2 + (d*d) -(2*c_ab) + (2*d*(sb-sa)); + if( p_squared < 0 ) { + return EDUBNOPATH; + } + double tmp1 = atan2( (ca-cb), tmp0 ); + double t = mod2pi( alpha - tmp1 ); + double p = sqrt( p_squared ); + double q = mod2pi( -beta + tmp1 ); + PACK_OUTPUTS(outputs); + return EDUBOK; +} + +int dubins_LSR( double alpha, double beta, double d, double* outputs ) +{ + UNPACK_INPUTS(alpha, beta); + double p_squared = -2 + (d*d) + (2*c_ab) + (2*d*(sa+sb)); + if( p_squared < 0 ) { + return EDUBNOPATH; + } + double p = sqrt( p_squared ); + double tmp2 = atan2( (-ca-cb), (d+sa+sb) ) - atan2(-2.0, p); + double t = mod2pi(-alpha + tmp2); + double q = mod2pi( -mod2pi(beta) + tmp2 ); + PACK_OUTPUTS(outputs); + return EDUBOK; +} + +int dubins_RSL( double alpha, double beta, double d, double* outputs ) +{ + UNPACK_INPUTS(alpha, beta); + double p_squared = (d*d) -2 + (2*c_ab) - (2*d*(sa+sb)); + if( p_squared< 0 ) { + return EDUBNOPATH; + } + double p = sqrt( p_squared ); + double tmp2 = atan2( (ca+cb), (d-sa-sb) ) - atan2(2.0, p); + double t = mod2pi(alpha - tmp2); + double q = mod2pi(beta - tmp2); + PACK_OUTPUTS(outputs); + return EDUBOK; +} + +int dubins_RLR( double alpha, double beta, double d, double* outputs ) +{ + UNPACK_INPUTS(alpha, beta); + double tmp_rlr = (6. - d*d + 2*c_ab + 2*d*(sa-sb)) / 8.; + if( fabs(tmp_rlr) > 1) { + return EDUBNOPATH; + } + double p = mod2pi( 2*M_PI - acos( tmp_rlr ) ); + double t = mod2pi(alpha - atan2( ca-cb, d-sa+sb ) + mod2pi(p/2.)); + double q = mod2pi(alpha - beta - t + mod2pi(p)); + PACK_OUTPUTS( outputs ); + return EDUBOK; +} + +int dubins_LRL( double alpha, double beta, double d, double* outputs ) +{ + UNPACK_INPUTS(alpha, beta); + double tmp_lrl = (6. - d*d + 2*c_ab + 2*d*(- sa + sb)) / 8.; + if( fabs(tmp_lrl) > 1) { + return EDUBNOPATH; + } + double p = mod2pi( 2*M_PI - acos( tmp_lrl ) ); + double t = mod2pi(-alpha - atan2( ca-cb, d+sa-sb ) + p/2.); + double q = mod2pi(mod2pi(beta) - alpha -t + mod2pi(p)); + PACK_OUTPUTS( outputs ); + return EDUBOK; +} + +/** + * @brief 计算路径长度 + * + * @param path :三个参数表示角度 + * @return double :返回值,表示路径长度 + */ +double dubins_path_length( DubinsPath* path ) +{ + double length = 0.; + length += path->param[0]; + length += path->param[1]; + length += path->param[2]; + length = length * path->rho; + return length; +} + +/** + * @brief 返回路径类型 + * + * @param path 输入:路径 + * @return int 返回值:路径类型 + */ +int dubins_path_type( DubinsPath* path ) { + return path->type; +} + +/** + * @brief 计算下一段Dubins路径段的位置 + * + * @param t 角度 + * @param qi 该段起始位置 + * @param qt 该段终点位置 + * @param type 路径类型 + */ +void dubins_segment( double t, double qi[3], double qt[3], int type) +{ + assert( type == L_SEG || type == S_SEG || type == R_SEG ); + //Shkel A M, Lumelsky V. Classification of the Dubins set[J]. Robotics and Autonomous Systems, 2001, 34(4): 179-202. + if( type == L_SEG ) {//公式 (1)的第一个式子,此处经过归一化后v=1 + qt[0] = qi[0] + sin(qi[2]+t) - sin(qi[2]); + qt[1] = qi[1] - cos(qi[2]+t) + cos(qi[2]); + qt[2] = qi[2] + t; + } + else if( type == R_SEG ) {//公式(1)的第二个式子,此处经过归一化后v=1 + qt[0] = qi[0] - sin(qi[2]-t) + sin(qi[2]); + qt[1] = qi[1] + cos(qi[2]-t) - cos(qi[2]); + qt[2] = qi[2] - t; + } + else if( type == S_SEG ) {//公式(1)的第三个式子,此处经过归一化后v=1 + qt[0] = qi[0] + cos(qi[2]) * t; + qt[1] = qi[1] + sin(qi[2]) * t; + qt[2] = qi[2]; + } +} + +/** + * @brief 对一段路径进行采样(根据路径长度t和路径参数path,生成长度为t的节点的位置) + * + * @param path 输入路径参数 + * @param t 路径长度t + * @param q 采样结果(线段终点的位置) + * @return int 返回值:非0表示出错,0表示正常 + */ +int dubins_path_sample( DubinsPath* path, double t, double q[3] ) +{ + if( t < 0 || t >= dubins_path_length(path) ) { + // error, parameter out of bounds + return EDUBPARAM; + } + + // tprime is the normalised variant of the parameter t + double tprime = t / path->rho; + + // In order to take rho != 1 into account this function needs to be more complex + // than it would be otherwise. The transformation is done in five stages. + // + // 1. translate the components of the initial configuration to the origin + // 2. generate the target configuration + // 3. transform the target configuration + // scale the target configuration + // translate the target configration back to the original starting point + // normalise the target configurations angular component + + // The translated initial configuration + // 将路径放在原点(0, 0),此时,只需要将角度保留即可 + double qi[3] = { 0, 0, path->qi[2] }; + + // Generate the target configuration + // 生成中间点的位置 + const int* types = DIRDATA[path->type]; + double p1 = path->param[0];//路径的第一个角度 + double p2 = path->param[1];//路径的第二个角度 + double q1[3]; // end-of segment 1 + double q2[3]; // end-of segment 2 + //从第qi点为起点,根据类型types[0],生成后一个点q1的configuration(即计算下一个节点的位置) + dubins_segment( p1, qi, q1, types[0] ); + //从第q1点为起点,根据类型types[1],生成后一个点q2的configuration(即计算下一个节点的位置) + dubins_segment( p2, q1, q2, types[1] ); + //生成q点的configuration + if( tprime < p1 ) { + dubins_segment( tprime, qi, q, types[0] ); + } + else if( tprime < (p1+p2) ) { + dubins_segment( tprime-p1, q1, q, types[1] ); + } + else { + dubins_segment( tprime-p1-p2, q2, q, types[2] ); + } + + // scale the target configuration, translate back to the original starting point + q[0] = q[0] * path->rho + path->qi[0]; + q[1] = q[1] * path->rho + path->qi[1]; + q[2] = mod2pi( q[2] ); + + return 0; +} + +/** + * @brief 通过回调函数多次调用dubins_path_sample + * + * @param path + * @param cb + * @param stepSize + * @param user_data + * @return int + */ +int dubins_path_sample_many( DubinsPath* path, DubinsPathSamplingCallback cb, double stepSize, void* user_data ) +{ + double x = 0.0; + double length = dubins_path_length(path); + while( x < length ) { + double q[3]; + dubins_path_sample( path, x, q ); + int retcode = cb(q, x, user_data); + if( retcode != 0 ) { + return retcode; + } + x += stepSize; + } + return 0; +} + +/** + * @brief 根据路径参数path, 返回线段末节点参数 + * + * @param path + * @param q + * @return int + */ +int dubins_path_endpoint( DubinsPath* path, double q[3] ) +{ + // TODO - introduce a new constant rather than just using EPSILON + return dubins_path_sample( path, dubins_path_length(path) - EPSILON, q ); +} + +/** + * @brief 将一段路径path,按路径长度t,划分为多个子线段。 + * + * @param path 输入的路径 + * @param t 子线段长度 + * @param newpath 生成的新的路径 + * @return int + */ +int dubins_extract_subpath( DubinsPath* path, double t, DubinsPath* newpath ) +{ + // calculate the true parameter + double tprime = t / path->rho; + + // copy most of the data + newpath->qi[0] = path->qi[0]; + newpath->qi[1] = path->qi[1]; + newpath->qi[2] = path->qi[2]; + newpath->rho = path->rho; + newpath->type = path->type; + + // fix the parameters + newpath->param[0] = fmin( path->param[0], tprime ); + newpath->param[1] = fmin( path->param[1], tprime - newpath->param[0]); + newpath->param[2] = fmin( path->param[2], tprime - newpath->param[0] - newpath->param[1]); + return 0; +} +} +#endif diff --git a/Src/hybrid_astar_planner-main/src/hybrid_astar.cpp b/Src/hybrid_astar_planner-main/src/hybrid_astar.cpp new file mode 100644 index 00000000..9ab1847a --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/hybrid_astar.cpp @@ -0,0 +1,280 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + * Email: dengpw@stu.xmu.edu.cn + *********************************************************************/ +#include "node3d.h" +#include +#include "constants.h" +#include "hybrid_astar.h" +#include +#include "visualize.h" +// #define SearchingVisulize +// #define debug_mode +namespace hybrid_astar_planner { + +bool hybridAstar::calculatePath( + const geometry_msgs::PoseStamped& start, + const geometry_msgs::PoseStamped& goal, + int cellsX, int cellsY, std::vector& plan, + ros::Publisher& pub, visualization_msgs::MarkerArray& pathNodes) { + #ifdef debug_mode + ros::Time t0 = ros::Time::now(); + #endif + // 初始化优先队列,未来改善混合A*算法性能,这里使用的是二项堆优先队列 + boost::heap::binomial_heap> openSet; + // 初始化并创建一些参数。 + // 创建charMap,charMap中存储的是地图的障碍物信息 + const unsigned char* charMap = costmap->getCharMap(); + + /**************************************************************** + * 分辨率太高会导致混合A*计算量过高,且意义不大, 因此 + * 这里把resolution写死,由于本人能力有限暂时此功,其实是无奈之举, + * 未来需要在后续的代码中加入能够自动调节分辨率的功能,增加代码鲁棒性 + ****************************************************************/ + float resolution = 0.125;//costmap->getResolution() + unsigned int originalX, originalY, goalX, goalY; + int cells_x,cells_y; + cells_x = cellsX/2.5; + cells_y = cellsY/2.5; + int counter = 0; + int dir; + int iPred, iSucc; + float t, g; + unsigned int dx,dy; + unsigned int goal_x, goal_y, start_x, start_y; + costmap->worldToMap(0, 0, dx, dy); + dx = dx/2.5; + dy = dy/2.5; + // t为目标点朝向 + t = tf::getYaw(start.pose.orientation); + Node3D* startPose = new Node3D(start.pose.position.x, start.pose.position.y, t , 0, 0, false, nullptr); + + costmap->worldToMap(goal.pose.position.x, + goal.pose.position.y, goal_x, goal_y); + costmap->worldToMap(start.pose.position.x, + start.pose.position.y, start_x, start_y); + + + //************************************************ + // 建立启发势场取决于地图大小,231(nodes/ms) + std::unordered_map> dp_map = + grid_a_star_heuristic_generator_->GenerateDpMap(goal_x, goal_y, costmap); + ros::Time end_time = ros::Time::now(); + #ifdef debug_mode + ros::Time t1 = ros::Time::now(); + ros::Duration d(end_time - t0); + std::cout << "generate heuristic map costed " << d * 1000 << " ms" < open_set; + std::unordered_map closed_set; + + if (Constants::reverse) { + dir = 6; + } + else { + dir = 3; + } + open_set.emplace(startPose->getindex(cells_x ,Constants::headings, resolution, dx, dy), startPose); + openSet.push(startPose); + Node3D* tmpNode; + Node3D* nSucc; + + while(openSet.size() && counter < Constants::iterations) { + ++counter; + // 根据混合A*算法,取堆顶的元素作为下查找节点 + tmpNode = openSet.top(); + + #ifdef SearchingVisulize + publishSearchNodes(*tmpNode, pub, pathNodes,counter); + #endif + + openSet.pop(); //出栈 + if ( reachGoal(tmpNode, goalPose) ) { + #ifdef debug_mode + ros::Time t1 = ros::Time::now(); + ros::Duration d(t1 - t0); + std::cout << "got plan in ms: " << d * 1000 << std::endl; + #endif + ROS_INFO("Got a plan,loop %d times", counter); + nodeToPlan(tmpNode, plan); + return true; + } + else { + if (Constants::dubinsShot && tmpNode->isInRange(*goalPose) && !tmpNode->isReverse()) { + nSucc = dubinsShot(*tmpNode, *goalPose, costmap); + //如果Dubins方法能直接命中,即不需要进入Hybrid A*搜索了,直接返回结果 + if (nSucc != nullptr && reachGoal(nSucc, goalPose) ) { + #ifdef debug_mode + ros::Time t1 = ros::Time::now(); + ros::Duration d(t1 - t0); + std::cout << "got plan in ms: " << d * 1000 << std::endl; + #endif + ROS_INFO("Got a plan,expored %d nodes ", counter); + nodeToPlan(nSucc, plan); + return true;//如果下一步是目标点,可以返回了 + } + } + else if(Constants::reedsSheppShot && tmpNode->isInRange(*goalPose) && !tmpNode->isReverse()) { + nSucc = reedsSheppShot(*tmpNode, *goalPose, costmap); + //如果Dubins方法能直接命中,即不需要进入Hybrid A*搜索了,直接返回结果 + if (nSucc != nullptr && reachGoal(nSucc, goalPose) ) { + #ifdef debug_mode + ros::Time t1 = ros::Time::now(); + ros::Duration d(t1 - t0); + std::cout << "got plan in ms: " << d * 1000 << std::endl; + #endif + ROS_INFO("Got a plan,expored %d nodes ", counter); + nodeToPlan(nSucc, plan); + return true;//如果下一步是目标点,可以返回了 + } + } + } + // 拓展tmpNode临时点目标周围的点,并且使用STL标准库的向量链表进行存储拓展点Node3D的指针数据 + std::vector adjacentNodes = gatAdjacentPoints(dir, cellsX, cellsY, charMap, tmpNode); + // 将 tmpNode点在pathNode3D中映射的点加入闭集合中 + closed_set.emplace(tmpNode->getindex(cells_x ,Constants::headings, resolution, dx, dy), tmpNode); + for (std::vector::iterator it = adjacentNodes.begin(); it != adjacentNodes.end(); ++it) { + // 使用stl标准库中的interator迭代器遍历相邻点 + Node3D* point = *it; + iPred = point->getindex(cells_x, Constants::headings, resolution, dx, dy); + if(closed_set.find(iPred)!= closed_set.end()) { + continue; + } + g = point->calcG(); + if(open_set.find(iPred)!= open_set.end()) { + if(g < open_set[iPred]->getG()) { + point->setG(g); + open_set[iPred]->setG(g); + openSet.push(point); // 如果符合拓展点要求,则将此点加入优先队列中 + } + } else { + point->setG(g); + open_set.emplace(iPred, point); + costmap->worldToMap(point->getX(), point->getY(), start_x, start_y); + updateH(*point, *goalPose, NULL, NULL, cells_x, cells_y, dp_map[start_y * cellsX + start_x]->getG()/20); + openSet.push(point); // 如果符合拓展点要求,则将此点加入优先队列中 + } + + } + } + return false; +} + +std::vector hybridAstar::gatAdjacentPoints(int dir, int cells_x, + int cells_y, const unsigned char* charMap, Node3D *point) { + std::vector adjacentNodes; + Node3D *tmpPtr; + float xSucc; + float ySucc; + float tSucc; + unsigned int startX, startY; + float t = point->getT(); + // int index; + float x = point->getX(); + float y = point->getY(); + unsigned int u32_x = int(x); + unsigned int u32_y = int(y); + for (int i = 0; i < dir; i++) { + if (i < 3) { + xSucc = x + Constants::dx[i] * cos(t) - Constants::dy[i] * sin(t); + ySucc = y + Constants::dx[i] * sin(t) + Constants::dy[i] * cos(t); + } else { + xSucc = x - Constants::dx[i - 3] * cos(t) - Constants::dy[i - 3] * sin(t); + ySucc = y - Constants::dx[i - 3] * sin(t) + Constants::dy[i - 3] * cos(t); + } + if (costmap->worldToMap(xSucc, ySucc, startX, startY)) { + + if (charMap[startX + startY * cells_x] < 250) { + if (i < 3) { + tmpPtr = new Node3D(xSucc, ySucc, t + Constants::dt[i], 999, 0, false, point); + tmpPtr->setCost(charMap[startX + startY * cells_x]); + } else { + tmpPtr = new Node3D(xSucc, ySucc, t - Constants::dt[i - 3], 999, 0, true, point); + tmpPtr->setCost(charMap[startX + startY * cells_x]); + } + adjacentNodes.push_back(tmpPtr); + } + } + } + + return adjacentNodes; +} + +bool hybridAstar::reachGoal(Node3D* node, Node3D* goalPose) { + float nodeX = node->getX(); + float nodeY = node->getY(); + float goalX = goalPose->getX(); + float goalY = goalPose->getY(); + if ((nodeX < (goalX + point_accuracy) && nodeX > (goalX - point_accuracy)) && + (nodeY < (goalY + point_accuracy) && nodeY > (goalY - point_accuracy)) ) { + if (node->getT() < (goalPose->getT()+theta_accuracy )&& + node->getT() > (goalPose->getT()-theta_accuracy )) { + return true; + } + } + return false; +} + +int hybridAstar::calcIndix(float x, float y, int cells_x, float t) { + return (int(x) * cells_x + int(y)) * Constants::headings + int(t / Constants::headings); +} + +void hybridAstar::nodeToPlan(Node3D* node, std::vector& plan) { + Node3D* tmpPtr = node; + geometry_msgs::PoseStamped tmpPose; + std::vector replan; + // float resolution = costmap->getResolution(); + unsigned int originalX,originalY; + tmpPose.header.stamp = ros::Time::now(); + //参数后期处理,发布到RViz上进行可视化 + while(tmpPtr!=nullptr) { + tmpPose.pose.position.x = tmpPtr->getX(); + tmpPose.pose.position.y = tmpPtr->getY(); + tmpPose.header.frame_id = frame_id_; + tmpPose.pose.orientation = tf::createQuaternionMsgFromYaw(tmpPtr->getT()); + replan.push_back(tmpPose); + tmpPtr = tmpPtr->getPerd(); + } + int size = replan.size(); + for (int i = 0;i < size; ++i) { + plan.push_back(replan[size - i -1 ]); + } + +} + +}//end of namespace hybrid_astar_planner diff --git a/Src/hybrid_astar_planner-main/src/node2d.cpp b/Src/hybrid_astar_planner-main/src/node2d.cpp new file mode 100644 index 00000000..ddb76d69 --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/node2d.cpp @@ -0,0 +1,133 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + *********************************************************************/ +#include "node2d.h" +#include +namespace hybrid_astar_planner { + +float Node2D::calcG(Node2D const *partent) { + float g; + if((abs(x - partent->x) + abs(y - partent->y)) == 2) { + g = 1.4142; + } + else g = 1; + return g + partent->getG() + 0.1*cost; +} + +float Node2D::calcH(Node2D const *goal) { + float dx, dy; + dx = abs(x - goal->x); + dy = abs(y - goal->y); + h = dx + dy; +} + +std::unordered_map> GridSearch::GenerateDpMap( + const double goal_x, const double goal_y, + costmap_2d::Costmap2D* costmap) { + const unsigned char* charMap = costmap->getCharMap(); + int counter = 0; + int cells_x, cells_y; + cells_x = costmap->getSizeInCellsX(); + cells_y = costmap->getSizeInCellsY(); + float resolution = costmap->getResolution(); + std::priority_queue, + std::vector>, cmp> + open_pq; + std::unordered_map> open_set; + std::unordered_map> dp_map_; + std::shared_ptr goal_node = std::make_shared(goal_x, goal_y); + goal_node->setX( goal_x ); + goal_node->setY( goal_y ); + goal_node->setG(0); + open_set.emplace(goal_node->getindex(cells_x), goal_node ); + open_pq.emplace(goal_node->getindex(cells_x), goal_node->getG()); + while(!open_pq.empty()) { + ++counter; + int id = open_pq.top().first; + open_pq.pop(); + std::shared_ptr current_node = open_set[id]; + dp_map_.emplace(current_node->getindex(cells_x), current_node); + std::vector> adjacent_nodes = + getAdjacentPoints(cells_x, cells_y, charMap, current_node ); + for (std::vector>::iterator + it = adjacent_nodes.begin(); it != adjacent_nodes.end(); ++it) { + std::shared_ptr next_node = *it; + if (dp_map_.find(next_node->getindex(cells_x)) != dp_map_.end()) { + continue; + } + if (open_set.find(next_node->getindex(cells_x)) != open_set.end()) { + if (open_set[next_node->getindex(cells_x)]->getG() > next_node->getG()) { + open_set[next_node->getindex(cells_x)]->setCost(next_node->getG()); + open_set[next_node->getindex(cells_x)]->setPerd_(current_node); + } + } else { + // ++counter; + next_node->setPerd_(current_node); + open_set.emplace(next_node->getindex(cells_x), next_node ); + open_pq.emplace(next_node->getindex(cells_x), next_node->getG()); + } + } + } + // printf("X %d y %d explored node num is : %d \n", cells_x, cells_y, counter); + return dp_map_; +} + +std::vector> GridSearch::getAdjacentPoints(int cells_x, + int cells_y, const unsigned char* charMap, std::shared_ptr point) { + std::vector> adjacentNodes; + float g = 0; + // std::cout << "the cost-so-far of this node" << point->getG() << std::endl; + for (int x = point->getX() - 1; x <= point->getX() + 1; ++x) { + for (int y = point->getY() - 1; y <= point->getY() + 1; ++y) { + if (charMap[x + y* cells_x] < 250 &&x < cells_x && y < cells_y + && x > 0 && y > 0) { + std::shared_ptr node = std::make_shared(x,y); + if((abs(x - point->getX()) + abs(y - point->getY())) == 2) { + g = 1.4142; + } else { + g = 1; + } + node->SetPathCost(point->getG() + 0.1*charMap[x + y* cells_x] + g); + node->setX(x); + node->setY(y); + adjacentNodes.emplace_back(node); + } + } + }//end of for + return adjacentNodes; +} + +}//namespace hybrid_astar_planner diff --git a/Src/hybrid_astar_planner-main/src/node3d.cpp b/Src/hybrid_astar_planner-main/src/node3d.cpp new file mode 100644 index 00000000..9b570099 --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/node3d.cpp @@ -0,0 +1,109 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + *********************************************************************/ +#include "node3d.h" +#include +#include +// 设计启发函数 +namespace hybrid_astar_planner { + +void Node3D::setT(float _t) { + if (_t>3.1415) { + _t = _t - 6.283; + } + t = _t / Constants::deltaHeadingRad; +} + + +float Node3D::calcG() { + float g; + if(reverse) { + // 如果进行的是倒车,对倒车、转向、改变方向进行惩罚 + if (reverse != perd->reverse) { // 对改变行驶方向进行惩罚 + g = Constants::dx[0] * Constants::penaltyCOD * Constants::penaltyReversing; + } + else { + g = Constants::dx[0] * Constants::penaltyReversing; + } + } + else { + // 如果此时位车辆前进情况,对其进行响应的代价计算 + if (reverse != perd->reverse) { //对方向改变进行的惩罚 + g = Constants::dx[0] * Constants::penaltyCOD; + } + else { + if (t == perd->t) { + g = Constants::dx[0]; + } + else { + g = Constants::dx[0] * Constants::penaltyTurning; + } + } + } + return g + perd->getG(); +} + +float Node3D::calcH(Node3D const *goal) { + float dx, dy; + dx = fabs(x - goal->x); + dy = fabs(y - goal->y); + h = dx +dy; +} + + + +//################################################### +// IS IN RANGE +//################################################### +bool Node3D::isInRange(const Node3D& goal) const { + int random = rand() % 10 + 1;//产生位于[1, 10]的随机数 + float dx = std::abs(x - goal.x) / random; + float dy = std::abs(y - goal.y) / random; + return (dx * dx) + (dy * dy) < Constants::dubinsShotDistance;//距离的平方和在100以内则认为可达 +} + +//################################################### +// 3D NODE COMPARISON +//################################################### +//3d节点的比较函数:x和y同时相同、并且theta在一个阈值范围内时可以认为是同一个Node +bool Node3D::operator == (const Node3D& rhs) const { + return (int)x == (int)rhs.x && + (int)y == (int)rhs.y && + (std::abs(t - rhs.t) <= Constants::deltaHeadingRad || + std::abs(t - rhs.t) >= Constants::deltaHeadingNegRad); +} + +} // namespace hybrid_astar_planner \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/src/planner_core.cpp b/Src/hybrid_astar_planner-main/src/planner_core.cpp new file mode 100644 index 00000000..59923320 --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/planner_core.cpp @@ -0,0 +1,156 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + *********************************************************************/ +#include +#include "planner_core.h" +#include +#include +#include "astar.h" +#include "hybrid_astar.h" + +PLUGINLIB_EXPORT_CLASS(hybrid_astar_planner::HybridAStarPlanner, nav_core::BaseGlobalPlanner)//注册为类插件的声明 + +namespace hybrid_astar_planner { + +HybridAStarPlanner::HybridAStarPlanner(): + initialized_(false),costmap(NULL),resolution(1.0) { + std::cout << "creating the hybrid Astar planner" << std::endl; +} + + +void HybridAStarPlanner::initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros) +{ + initialize(name, costmap_ros->getCostmap(), costmap_ros->getGlobalFrameID()); +} + + +void HybridAStarPlanner::initialize(std::string name, costmap_2d::Costmap2D *_costmap, std::string frame_id) { + if(!initialized_) { + ROS_INFO("initializing the hybrid Astar planner"); + // 订阅global_costmap的内容,以便获取参数 + ros::NodeHandle nh("~/global_costmap"); + ros::NodeHandle nh2("~/"); + ros::NodeHandle private_nh("~/" + name); + nh2.param("use_hybrid_astar", use_hybrid_astar, true); + if(use_hybrid_astar) { + ROS_INFO("Using hybrid_astar mode!"); + } else { + ROS_INFO("Using Astar mode!"); + } + costmap = _costmap; + frame_id_ = frame_id; + std::cout << frame_id << std::endl; + // 初始化发布路径的主题 + plan_pub_ = private_nh.advertise("plan", 1); + path_vehicles_pub_ = private_nh.advertise("pathVehicle", 1); + make_plan_srv_ = private_nh.advertiseService("make_plan", &HybridAStarPlanner::makePlanService, this); + } + initialized_ = true; +}//end of constructor function HybridAStarPlanner + +HybridAStarPlanner::~HybridAStarPlanner() { + +}//end of deconstructor function HybridAStarPlanner + + +bool HybridAStarPlanner::makePlanService(nav_msgs::GetPlan::Request& req, + nav_msgs::GetPlan::Response& resp) { + makePlan(req.start, req.goal, resp.plan.poses); + resp.plan.header.stamp = ros::Time::now(); + resp.plan.header.frame_id = frame_id_; + return true; +} + + +bool HybridAStarPlanner::makePlan(const geometry_msgs::PoseStamped &start, + const geometry_msgs::PoseStamped &goal, + std::vector& plan) { + // std::cout << "the start pose of planner x:" << start.pose.position.x << " y:" << start.pose.position.y << std::endl; + // std::cout << "the goal pose of planner x:" << goal.pose.position.x << " y:" << goal.pose.position.y << std::endl; + Expander* _planner; + + // ROS_INFO("the resolution of cost map: %f ",costmap->getResolution()); + if (use_hybrid_astar) { + _planner = new hybridAstar(frame_id_,costmap); + } + else { + _planner = new astar(frame_id_,costmap); + } + + //检查设定的目标点参数是否合规 + if(!(checkStartPose(start) && checkgoalPose(goal))) { + ROS_WARN("Failed to create a global plan!"); + return false; + } + plan.clear(); + //正式将参数传入规划器中 + if(!_planner->calculatePath(start, goal , costmap->getSizeInCellsX(), costmap->getSizeInCellsY(), plan, path_vehicles_pub_, pathNodes)) { + return false; + } + + //参数后期处理,发布到RViz上进行可视化 + clearPathNodes(); + //path只能发布2D的节点 + publishPlan(plan); + publishPathNodes(plan); + return true; +}//end of makeplan + +bool HybridAStarPlanner::checkStartPose(const geometry_msgs::PoseStamped &start) { + unsigned int startx,starty; + if (costmap->worldToMap(start.pose.position.x, start.pose.position.y, startx, starty)) { + return true; + } + ROS_WARN("The Start pose is out of the map!"); + return false; +}//end of checkStartPose + +bool HybridAStarPlanner::checkgoalPose(const geometry_msgs::PoseStamped &goal) { + unsigned int goalx,goaly; + if (costmap->worldToMap(goal.pose.position.x, goal.pose.position.y, goalx, goaly)) { + if (costmap->getCost( goalx, goaly ) > 252) { + // std::cout << costmap->getCost(goalx, goaly) << std::endl; + ROS_WARN("The Goal pose is out of the map! %d",costmap->getCost(goalx, goaly)); + ROS_WARN("The Goal pose is occupied , please reset the goal!"); + return false; + } + return true; + } + return false; +}//end of checkgoalPose + +}//namespace hybrid_astar_planner + diff --git a/Src/hybrid_astar_planner-main/src/visualize.cpp b/Src/hybrid_astar_planner-main/src/visualize.cpp new file mode 100644 index 00000000..2f45ec2d --- /dev/null +++ b/Src/hybrid_astar_planner-main/src/visualize.cpp @@ -0,0 +1,139 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: dengpw + *********************************************************************/ +#include "planner_core.h" +#include "node3d.h" +#include +namespace hybrid_astar_planner { + +void HybridAStarPlanner::publishPlan(const std::vector& path) { + if (!initialized_) { + ROS_ERROR( + "This planner has not been initialized yet, but it is being used, please call initialize() before use"); + return; + } + //create a message for the plan + geometry_msgs::PoseStamped transform_path; + nav_msgs::Path gui_path; + int size = path.size(); + gui_path.poses.resize(size); + + gui_path.header.frame_id = frame_id_; + gui_path.header.stamp = ros::Time::now(); + + // Extract the plan in world co-ordinates, we assume the path is all in the same frame + for (unsigned int i = 0; i < size; i++) { + transform_path.pose.position = path[i].pose.position; + gui_path.poses[i] = transform_path;// + } + + plan_pub_.publish(gui_path); + // ROS_INFO("Publish the path to Rviz"); + +}//end of publishPlan + + +void HybridAStarPlanner::publishPathNodes(const std::vector& path) { + if (!initialized_) { + ROS_ERROR( + "This planner has not been initialized yet, but it is being used, please call initialize() before use"); + return; + } + visualization_msgs::Marker pathVehicle; + int nodeSize = path.size(); + pathVehicle.header.stamp = ros::Time(0); + pathVehicle.color.r = 52.f / 255.f; + pathVehicle.color.g = 250.f / 255.f; + pathVehicle.color.b = 52.f / 255.f; + pathVehicle.type = visualization_msgs::Marker::ARROW; + pathVehicle.header.frame_id = frame_id_; + pathVehicle.scale.x = 0.22; + pathVehicle.scale.y = 0.18; + pathVehicle.scale.z = 0.12; + pathVehicle.color.a = 0.1; + // 转化节点,并同时加上时间戳等信息 + for(int i = 0; i +#include +#include +#include +#include +class TestPlanner{ + public: + /** + * @brief Default constructor for the TestPlanner + * @param tf A reference to a TransformListener + */ + TestPlanner(tf2_ros::Buffer &tf); + /** + * @brief Destructor - Cleans up + **/ + ~TestPlanner(); + /** + * @brief Call back function of a suscriber 目的是接收RViz传过来的goal pose + * @param _goal A reference to geometry_msgs::PoseStamped::ConstPtr + */ + void setgoal(const geometry_msgs::PoseStamped::ConstPtr& _goal); + + private: + /** + * @brief Transform the Start pose from tf tree 将起始点从TF转化树中提取出来(测试程序将bese_link作为起始点提取) + * + */ + bool transformStarPose(void); + //智能指针,用来加载类插件,保存类插件的地址。这里没有使用标准库是因为Classloder的createInstance函数支持boost库,并没有使用标准库 + boost::shared_ptr planner_; + //路径规划的vector类模板,用来保存路径 + std::vector* planner_plan_; + geometry_msgs::PoseStamped goal_pose; + geometry_msgs::PoseStamped start_pose; + geometry_msgs::TransformStamped start_transform; + ros::NodeHandle n; + costmap_2d::Costmap2DROS* costmap; + geometry_msgs::PoseStamped robot_pose; + std::string global_planner; + tf2_ros::Buffer& tf; + ros::Subscriber make_plane; + +}; + +#endif //!_TEST_PLUGINS \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/launch/config.rviz b/Src/hybrid_astar_planner-main/test_the_plugin/launch/config.rviz new file mode 100644 index 00000000..a9c9b9be --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/launch/config.rviz @@ -0,0 +1,221 @@ +Panels: + - Class: rviz/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Map2 + - /Path1 + - /MarkerArray3 + Splitter Ratio: 0.5 + Tree Height: 300 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: "" +Preferences: + PromptSaveOnExit: true +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: map + Draw Behind: false + Enabled: true + Name: Map + Topic: /map + Unreliable: false + Use Timestamp: false + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 255; 25; 0 + Enabled: true + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Name: Pose + Shaft Length: 1 + Shaft Radius: 0.05000000074505806 + Shape: Arrow + Topic: /move_base_simple/goal + Unreliable: false + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 255; 25; 0 + Enabled: true + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Name: Pose + Shaft Length: 1 + Shaft Radius: 0.05000000074505806 + Shape: Arrow + Topic: /move_base_simple/start + Unreliable: false + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sPathNodes + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sPathVehicle + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Axes + Enabled: true + Length: 1 + Name: Axes + Radius: 0.10000000149011612 + Reference Frame: base_link + Value: true + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: costmap + Draw Behind: false + Enabled: true + Name: Map + Topic: /move_base/global_costmap/costmap + Unreliable: false + Use Timestamp: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 25; 255; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Lines + Line Width: 0.029999999329447746 + Name: Path + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/HybridAStarPlanner/plan + Unreliable: false + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /move_base/HybridAStarPlanner/pathVehicle + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Default Light: true + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/MoveCamera + - Class: rviz/Select + - Class: rviz/FocusCamera + - Class: rviz/Measure + - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 + Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Angle: 0.019999396055936813 + Class: rviz/TopDownOrtho + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Scale: 78.33514404296875 + Target Frame: + Value: TopDownOrtho (rviz) + X: 2.5319337844848633 + Y: 1.5114061832427979 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 597 + Hide Left Dock: false + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd000000040000000000000156000001b7fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000001b7000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000001b7fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000001b7000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004e40000003efc0100000002fb0000000800540069006d00650100000000000004e4000002eb00fffffffb0000000800540069006d0065010000000000000450000000000000000000000273000001b700000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1252 + X: 317 + Y: 27 diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/launch/test.launch b/Src/hybrid_astar_planner-main/test_the_plugin/launch/test.launch new file mode 100644 index 00000000..abafd3e1 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/launch/test.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/map.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/map.yaml new file mode 100644 index 00000000..957d4750 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/map.yaml @@ -0,0 +1,8 @@ +image: map_demo.png +resolution: 1 +origin: [0.0, 0.0, 0.0] +occupied_thresh: 0.1 +free_thresh: 0.05 +negate: 0 + + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/map_demo.png b/Src/hybrid_astar_planner-main/test_the_plugin/maps/map_demo.png new file mode 100644 index 00000000..778ebfa9 Binary files /dev/null and b/Src/hybrid_astar_planner-main/test_the_plugin/maps/map_demo.png differ diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mm.pgm b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mm.pgm new file mode 100644 index 00000000..2c830d2e --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mm.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +448 672 +255 + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mm.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mm.yaml new file mode 100644 index 00000000..d4832149 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mm.yaml @@ -0,0 +1,7 @@ +image: mm.pgm +resolution: 0.050000 +origin: [-1.000000, -12.200000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap.pgm b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap.pgm new file mode 100644 index 00000000..ff5bb085 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +1984 1984 +255 + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap.yaml new file mode 100644 index 00000000..3018cc80 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap.yaml @@ -0,0 +1,7 @@ +image: mymap.pgm +resolution: 0.050000 +origin: [-50.000000, -50.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2077.pgm b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2077.pgm new file mode 100644 index 00000000..e9f90196 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2077.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +288 512 +255 + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2077.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2077.yaml new file mode 100644 index 00000000..6a395155 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2077.yaml @@ -0,0 +1,7 @@ +image: mymap2077.pgm +resolution: 0.050000 +origin: [-7.000000, -7.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2088.pgm b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2088.pgm new file mode 100644 index 00000000..3e282e7e --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2088.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +288 288 +255 + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2088.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2088.yaml new file mode 100644 index 00000000..f9bbdb38 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap2088.yaml @@ -0,0 +1,7 @@ +image: mymap2088.pgm +resolution: 0.050000 +origin: [-7.000000, -7.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap4.pgm b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap4.pgm new file mode 100644 index 00000000..abbf26fa --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap4.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +1984 1984 +255 + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap4.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap4.yaml new file mode 100644 index 00000000..6ec1bd70 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap4.yaml @@ -0,0 +1,7 @@ +image: mymap4.pgm +resolution: 0.050000 +origin: [-50.000000, -50.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap5.pgm b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap5.pgm new file mode 100644 index 00000000..fb8a7e4b --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap5.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +672 448 +255 + \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap5.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap5.yaml new file mode 100644 index 00000000..09426b3e --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/maps/mymap5.yaml @@ -0,0 +1,7 @@ +image: mymap5.pgm +resolution: 0.050000 +origin: [-12.200000, -1.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/base_local_planner_params.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/param/base_local_planner_params.yaml new file mode 100644 index 00000000..ee11a5fe --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/base_local_planner_params.yaml @@ -0,0 +1,130 @@ +# TrajectoryPlannerROS: + +# meter_scoring: true +# holonomic_robot: false + +# max_vel_x: 0.6 +# min_vel_x: 0.1 + +# max_vel_y: 0 +# min_vel_y: 0 + +# max_vel_theta: 1.2 +# min_vel_theta: -1.2 + +# min_in_place_vel_theta: 0.5 +# escape_vel: -0.5 + +# acc_lim_theta: 1 +# acc_lim_x: 0.1 +# acc_lim_y: 0 +# xy_goal_tolerance: 0.15 +# yaw_goal_tolerance: 0.15 +TebLocalPlannerROS: + + odom_topic: odom + map_frame: /odom + + # Trajecto + + teb_autosize: True + dt_ref: 0.1 #期望的轨迹时间分辨率 + dt_hysteresis: 0.01 #根据当前时间分辨率自动调整大小的滞后现象,通常约为。建议使用dt ref的10% + + global_plan_overwrite_orientation: True #覆盖由全局规划器提供的局部子目标的方向 + max_global_plan_lookahead_dist: 3.0 #指定考虑优化的全局计划子集的最大长度 + feasibility_check_no_poses: 4 #每个采样间隔的姿态可行性分析数,default:4 + + + allow_init_with_backwards_motion: True + global_plan_viapoint_sep: -1 + global_plan_prune_distance: 1 + exact_arc_length: False + publish_feedback: False + + # Robot + max_vel_x: 5 + max_vel_x_backwards: 2 + max_vel_theta: 1 + acc_lim_x: 3 + acc_lim_theta: 1 + + #仅适用于全向轮 + # max_vel_y (double, default: 0.0) + # acc_lim_y (double, default: 0.5) + + # ********************** Carlike robot parameters ******************** + min_turning_radius: 1 # Min turning radius of the carlike robot (compute value using a model or adjust with rqt_reconfigure manually) + wheelbase: 0.325 # Wheelbase of our robot + cmd_angle_instead_rotvel: True # stage simulator takes the angle instead of the rotvel as input (twist message) + # ******************************************************************** + + footprint_model: # types: "point", "circular", "two_circles", "line", "polygon" + type: "line" + # radius: 0.2 # for type "circular" + line_start: [-0.2, 0.0] # for type "line" + line_end: [0.2, 0.0] # for type "line" + # front_offset: 0.2 # for type "two_circles" + # front_radius: 0.2 # for type "two_circles" + # rear_offset: 0.2 # for type "two_circles" + # rear_radius: 0.2 # for type "two_circles" + # vertices: [ [0.25, -0.05], [0.18, -0.05], [0.18, -0.18], [-0.19, -0.18], [-0.25, 0], [-0.19, 0.18], [0.18, 0.18], [0.18, 0.05], [0.25, 0.05] ] # for type "polygon" + + # GoalTolerance + + xy_goal_tolerance: 0.2 + yaw_goal_tolerance: 0.1 + free_goal_vel: False + # complete_global_plan: True + # Obstacles + + min_obstacle_dist: 0.1 #0.3 # 与障碍的最小期望距离,注意,teb_local_planner本身不考虑膨胀半径 + include_costmap_obstacles: True #应否考虑到局部costmap的障碍 + costmap_obstacles_behind_robot_dist: 0.3 #考虑后面n米内的障碍物 + obstacle_poses_affected: 30 #为了保持距离,每个障碍物位置都与轨道上最近的位置相连。 + costmap_converter_plugin: "" + costmap_converter_spin_thread: True + costmap_converter_rate: 5 + + # Optimization + + no_inner_iterations: 5 + no_outer_iterations: 4 + optimization_activate: True + optimization_verbose: False + penalty_epsilon: 0.1 + weight_max_vel_x: 2 + weight_max_vel_theta: 1 + weight_acc_lim_x: 1 + weight_acc_lim_theta: 1 + weight_kinematics_nh: 1000 + weight_kinematics_forward_drive: 1 + weight_kinematics_turning_radius: 1 + weight_optimaltime: 1 + weight_obstacle: 50 + weight_dynamic_obstacle: 10 # not in use yet + alternative_time_cost: False # not in use yet + selection_alternative_time_cost: False + # Homotopy Class Planner + + enable_homotopy_class_planning: False + enable_multithreading: False + simple_exploration: False + max_number_classes: 4 + roadmap_graph_no_samples: 15 + roadmap_graph_area_width: 5 + h_signature_prescaler: 0.5 + h_signature_threshold: 0.1 + obstacle_keypoint_offset: 0.1 + obstacle_heading_threshold: 0.45 + visualize_hc_graph: False + + # # Recovery + + # shrink_horizon_backup: True + # shrink_horizon_min_duration: 10 + # oscillation_recovery: True + # oscillation_v_eps: 0.1 + # oscillation_omega_eps: 0.1 + # oscillation_recovery_min_duration: 10 + # oscillation_filter_duration: 10 \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/costmap_common_params.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/param/costmap_common_params.yaml new file mode 100644 index 00000000..8950ac10 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/costmap_common_params.yaml @@ -0,0 +1,22 @@ +obstacle_range: 2.5 +raytrace_range: 3.5 +# footprint: [[-0.08, -0.15], [-0.08, 0.15],[0.42, 0.15], [0.42, -0.15]] +robot_radius: 0.1 +inflation_radius: 0.5 +transform_tolerance: 0.6 +observation_sources: scan +# obstacles: +# observation_sources: scan +# scan: {data_type: LaserScan, topic: /scan, marking: true, clearing: true, expected_update_rate: 0} +map: + data_type: LaserScan + topic: /map + marking: true + clearing: true +scan: + data_type: LaserScan + topic: scan + marking: true + clearing: true + +map_type: costmap \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/costmap_common_params_mark.txt b/Src/hybrid_astar_planner-main/test_the_plugin/param/costmap_common_params_mark.txt new file mode 100644 index 00000000..9376ce7f --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/costmap_common_params_mark.txt @@ -0,0 +1,23 @@ +这些参数设置了代价图中的障碍物信息的阈值。 +obstacle_range: 2.5 #此参数确定了最大范围传感器读数,在此范围内的障碍物将会被标记并放入代价图中 +raytrace_range: 3.5 #这个范围内不存在的障碍物都会被清除 +# footprint: [[-0.08, -0.15], [-0.08, 0.15],[0.42, 0.15], [0.42, -0.15]] +robot_radius: 0.15 +inflation_radius: 0.8 +transform_tolerance: 0.6 +observation_sources: scan +# obstacles: +# observation_sources: scan +# scan: {data_type: LaserScan, topic: /scan, marking: true, clearing: true, expected_update_rate: 0} +map: + data_type: LaserScan + topic: /map + marking: true + clearing: true +scan: + data_type: LaserScan + topic: scan + marking: true + clearing: true + +map_type: costmap \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/global_costmap_params.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/param/global_costmap_params.yaml new file mode 100644 index 00000000..c653287d --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/global_costmap_params.yaml @@ -0,0 +1,16 @@ +global_costmap: + global_frame: map + robot_base_frame: base_link + update_frequency: 1.0 + publish_frequency: 0.5 + static_map: true + transform_tolerance: 0.5 + cost_scaling_factor: 10.0 + # inflation_radius: 0.4 + resolution: 1.0 + plugins: + - {name: static_map, type: "costmap_2d::StaticLayer"} + - {name: obstacles, type: "costmap_2d::VoxelLayer"} + - {name: inflation_layer, type: "costmap_2d::InflationLayer"} + + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/local_costmap_params.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/param/local_costmap_params.yaml new file mode 100644 index 00000000..7be342e1 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/local_costmap_params.yaml @@ -0,0 +1,13 @@ +local_costmap: + global_frame: map + robot_base_frame: base_link + update_frequency: 5.0 + publish_frequency: 2.0 + static_map: false + rolling_window: true + width: 5 + height: 5 + resolution: 0.05 + transform_tolerance: 0.5 + cost_scaling_factor: 5 + # inflation_radius: 0.3 diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/move_base_params.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/param/move_base_params.yaml new file mode 100644 index 00000000..c94122fe --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/move_base_params.yaml @@ -0,0 +1,13 @@ +shutdown_costmaps: false + +controller_frequency: 5.0 +controller_patience: 3.0 + +planner_frequency: 0.5 +planner_patience: 5.0 + +oscillation_timeout: 10.0 +oscillation_distance: 0.2 + +conservative_reset_dist: 0.1 + diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/param/plugins.yaml b/Src/hybrid_astar_planner-main/test_the_plugin/param/plugins.yaml new file mode 100644 index 00000000..3501cae3 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/param/plugins.yaml @@ -0,0 +1,5 @@ +plugins: [] +plugins: + - {name: static_map, type: "costmap_2d::StaticLayer"} + - {name: obstacles, type: "costmap_2d::VoxelLayer"} + - {name: inflation_layer, type: "costmap_2d::InflationLayer"} \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/src/test.cpp b/Src/hybrid_astar_planner-main/test_the_plugin/src/test.cpp new file mode 100644 index 00000000..47a7fbe4 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/src/test.cpp @@ -0,0 +1,54 @@ +/** + @file test.cpp + @brief Main entry point of the test program, the test program is using to test the hybrid_Astar plugin of + move_base package. + @author dengpw 2021/02/21 +*/ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *********************************************************************/ +#include +#include "test_plugins.h" +int main(int argc, char** argv) { + ros::init(argc,argv,"plugin_test_node"); + //ros::Duration(10)代表10秒的时间,在这里表示'tf2_ros::Buffer'实例化的对象保留10秒内的转换数据 + tf2_ros::Buffer buffer(ros::Duration(10)); + //监听转换 + tf2_ros::TransformListener tf(buffer); + TestPlanner test( buffer ); + + ros::spin(); + return 0; +} \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/src/test_plugins.cpp b/Src/hybrid_astar_planner-main/test_the_plugin/src/test_plugins.cpp new file mode 100644 index 00000000..17484c09 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/src/test_plugins.cpp @@ -0,0 +1,106 @@ +/********************************************************************* + * + * BSD 3-Clause License + * + * Copyright (c) 2021, dengpw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1 Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3 Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *********************************************************************/ +#include +#include +#include +#include +#include "test_plugins.h" + +TestPlanner::TestPlanner(tf2_ros::Buffer &_tf): +tf(_tf){ + //订阅目标主题,绑定响应函数,这里使用suscribe订阅目标点,当目标点刷新就重新进行路径规划 + make_plane = n.subscribe("/move_base_simple/goal", 1, &TestPlanner::setgoal, this); + //定义类插件的名称,以便之后接入系统 + global_planner = std::string("hybrid_astar_planner/HybridAStarPlanner"); + // ros::NodeHandle nh("~/global_costmap"); + pluginlib::ClassLoader bgp_loader_("nav_core", "nav_core::BaseGlobalPlanner"); //导入插件 + planner_plan_ = new std::vector(); + //这个global_costmap,是它自己的名字,这里需要用param服务器给到costmap的参数,才会初始化 + + // 需要注意的是,这里的初始化函数Costmap2DROS在构造时候的问题,~代表的是私有域的数据 + costmap = new costmap_2d::Costmap2DROS("global_costmap", tf); + + std::cout << "creat the global costmap" << std::endl; + //指定costmap中的base_link为起始坐标 + robot_pose.header.frame_id = "base_link"; + + transformStarPose(); + try + { + planner_=bgp_loader_.createInstance(global_planner); + planner_->initialize(bgp_loader_.getName(global_planner),costmap); + } + catch (const pluginlib::PluginlibException &ex) + { + ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", global_planner.c_str(), ex.what()); + exit(1); + } +} +void TestPlanner::setgoal(const geometry_msgs::PoseStamped::ConstPtr& _goal) { + // std::cout << "receved the goal pose" <pose; + goal_pose.pose.orientation = _goal->pose.orientation; + goal_pose.header = _goal->header; + transformStarPose(); + costmap->start(); + planner_->makePlan(start_pose, goal_pose, *planner_plan_); +} + +bool TestPlanner::transformStarPose(void){ + try + { + start_transform = tf.lookupTransform("map", "base_link", ros::Time(0), ros::Duration(3.0)); + } + catch(const std::exception& e) + { + std::cerr << e.what() << '\n'; + return false; + } + start_pose.pose.position.x = start_transform.transform.translation.x; + start_pose.pose.position.y = start_transform.transform.translation.y; + start_pose.pose.position.z = start_transform.transform.translation.z; + start_pose.pose.orientation.w = start_transform.transform.rotation.w; + start_pose.pose.orientation.x = start_transform.transform.rotation.x; + start_pose.pose.orientation.y = start_transform.transform.rotation.y; + start_pose.pose.orientation.z = start_transform.transform.rotation.z; + return true; +} +TestPlanner::~TestPlanner() { + planner_.reset(); + if(costmap) { + delete costmap; + } +} \ No newline at end of file diff --git a/Src/hybrid_astar_planner-main/test_the_plugin/src/tf_broadcaster.cpp b/Src/hybrid_astar_planner-main/test_the_plugin/src/tf_broadcaster.cpp new file mode 100644 index 00000000..5a1e4932 --- /dev/null +++ b/Src/hybrid_astar_planner-main/test_the_plugin/src/tf_broadcaster.cpp @@ -0,0 +1,84 @@ +/** + * @file tf_broadcaster.cpp + * @brief 这时实现了一个坐标系统转换的TF变换: + * 1) odom -> map + * 2) map -> path + * 3) map -> base_link + */ + +//################################################### +// TF MODULE FOR THE HYBRID A* +// 用于测试混合A*算法的一个模组 +//################################################### +#include +#include +#include +#include +#include +// map pointer +nav_msgs::OccupancyGridPtr grid;//定义广播信息的格式 +tf::Transform transform; //创建tf的广播器 +tf::Quaternion q; + +// map callback +void setMap(const nav_msgs::OccupancyGrid::Ptr map) { + std::cout << "Creating transform for map..." << std::endl; + grid = map; +} + +void start_pose_callback(const geometry_msgs::PoseWithCovarianceStampedPtr& post) { + + // 初始化tf数据 + transform.setOrigin(tf::Vector3(post->pose.pose.position.x, post->pose.pose.position.y, 0.0)); + //定义旋转的四元参数 + //具体的TF变换内容可以参考《机器人学导论》(美)克来格(Craig,J.J) + q.setX(post->pose.pose.orientation.x); + q.setY(post->pose.pose.orientation.y); + q.setZ(post->pose.pose.orientation.z); + q.setW(post->pose.pose.orientation.w); + transform.setRotation(q); + // 广播world与base_link之间的tf数据 + + std::cout << "Transform initialpost to base_link" << std::endl; +} + +int main(int argc, char** argv) { + // initiate the broadcaster + ros::init(argc, argv, "tf_broadcaster"); + ros::NodeHandle n; + ros::NodeHandle nh; + // subscribe to map updates + std::cout << "Transform initialpost to base_link" << std::endl; + ros::Subscriber sub_map = n.subscribe("/occ_map", 1, setMap); + ros::Subscriber sub_start = nh.subscribe("/initialpose", 1, &start_pose_callback); + tf::Pose tfPose; + ros::Rate r(10); + tf::TransformBroadcaster broadcaster; + tf::TransformBroadcaster br; + transform.setOrigin(tf::Vector3(0, 0, 0.0)); + q.setX(0); + q.setY(0); + q.setZ(0); + q.setW(1); + transform.setRotation(q); + while (ros::ok()) { + // transform from geometry msg to TF + if (grid != nullptr) { + tf::poseMsgToTF(grid->info.origin, tfPose); + } + // listener + // odom to map 从odom到地图坐标系 + broadcaster.sendTransform( + tf::StampedTransform( + tf::Transform(tf::Quaternion(0, 0, 0, 1), tfPose.getOrigin()), + ros::Time::now(), "odom", "map")); + // map to path 从map到路径坐标系,这里的路径坐标系是三维的坐标系 + broadcaster.sendTransform( + tf::StampedTransform( + tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0, 0, 0)), + ros::Time::now(), "map", "path")); + br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "map", "base_link")); + ros::spinOnce(); + r.sleep(); + } +}