mesh_controller.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020, Sebastian Pütz, Sabrina Frohn
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following
13  * disclaimer in the documentation and/or other materials provided
14  * with the distribution.
15  *
16  * 3. Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * authors:
34  * Sebastian Pütz <spuetz@uos.de>
35  *
36  */
37 
39 #include <lvr2/util/Meap.hpp>
40 #include <mbf_msgs/ExePathResult.h>
41 #include <mbf_msgs/GetPathResult.h>
43 #include <mesh_map/util.h>
45 #include <std_msgs/Float32.h>
48 
50 
51 #define DEBUG
52 
53 #ifdef DEBUG
54 #define DEBUG_CALL(method) method
55 #else
56 #define DEBUG_CALL(method)
57 #endif
58 
59 namespace mesh_controller
60 {
62 {
63 }
64 
66 {
67 }
68 
69 uint32_t MeshController::computeVelocityCommands(const geometry_msgs::PoseStamped& pose,
70  const geometry_msgs::TwistStamped& velocity,
71  geometry_msgs::TwistStamped& cmd_vel, std::string& message)
72 {
73  const auto& mesh = map_ptr->mesh();
74 
77  std::array<float, 3> bary_coords;
78  std::array<mesh_map::Vector, 3> vertices;
79 
80  if (!current_face)
81  {
82  // initially search current face on complete map
83  if (auto search_res_opt = map_ptr->searchContainingFace(
84  robot_pos, config.max_search_distance))
85  {
86  auto search_res = *search_res_opt;
87  current_face = std::get<0>(search_res);
88  vertices = std::get<1>(search_res);
89  bary_coords = std::get<2>(search_res);
90 
91  // project position onto surface
92  robot_pos = mesh_map::linearCombineBarycentricCoords(vertices, bary_coords);
93  }
94  else
95  {
96  // no corresponding face has been found
97  return mbf_msgs::ExePathResult::OUT_OF_MAP;
98  }
99  }
100  else // current face is set
101  {
103  vertices = mesh.getVertexPositionsOfFace(face);
104  DEBUG_CALL(map_ptr->publishDebugFace(face, mesh_map::color(1, 1, 1), "current_face");)
105  DEBUG_CALL(map_ptr->publishDebugPoint(robot_pos, mesh_map::color(1, 1, 1), "robot_position");)
106 
107  float dist_to_surface;
108  // check whether or not the position matches the current face
109  // if not search for new current face
111  robot_pos, vertices, bary_coords, dist_to_surface)
112  && dist_to_surface < config.max_search_distance)
113  {
114  // current position is located inside and close enough to the face
115  DEBUG_CALL(map_ptr->publishDebugPoint(robot_pos, mesh_map::color(0, 0, 1), "current_position");)
116  }
117  else if (auto search_res_opt = map_ptr->searchNeighbourFaces(
118  robot_pos, face, config.max_search_radius, config.max_search_distance))
119  {
120  // new face has been found out of the neighbour faces of the current face
121  // update variables to new face
122  auto search_res = *search_res_opt;
123  current_face = face = std::get<0>(search_res);
124  vertices = std::get<1>(search_res);
125  bary_coords = std::get<2>(search_res);
126  robot_pos = mesh_map::linearCombineBarycentricCoords(vertices, bary_coords);
127  DEBUG_CALL(map_ptr->publishDebugFace(face, mesh_map::color(1, 0.5, 0), "search_neighbour_face");)
128  DEBUG_CALL(map_ptr->publishDebugPoint(robot_pos, mesh_map::color(0, 0, 1), "search_neighbour_pos");)
129  }
130  else if(auto search_res_opt = map_ptr->searchContainingFace(
131  robot_pos, config.max_search_distance))
132  {
133  // update variables to new face
134  auto search_res = *search_res_opt;
135  current_face = face = std::get<0>(search_res);
136  vertices = std::get<1>(search_res);
137  bary_coords = std::get<2>(search_res);
138  robot_pos = mesh_map::linearCombineBarycentricCoords(vertices, bary_coords);
139  }
140  else
141  {
142  // no corresponding face has been found
143  return mbf_msgs::ExePathResult::OUT_OF_MAP;
144  }
145  }
146 
147  const lvr2::FaceHandle& face = current_face.unwrap();
148  std::array<lvr2::VertexHandle, 3> handles = map_ptr->mesh_ptr->getVerticesOfFace(face);
149 
150  // update to which position of the plan the robot is closest
151 
152  const auto& opt_dir = map_ptr->directionAtPosition(vector_map, handles, bary_coords);
153  if (!opt_dir)
154  {
155  DEBUG_CALL(map_ptr->publishDebugFace(face, mesh_map::color(0.3, 0.4, 0), "no_directions");)
156  ROS_ERROR_STREAM("Could not access vector field for the given face!");
157  return mbf_msgs::ExePathResult::FAILURE;
158  }
159  mesh_map::Normal mesh_dir = opt_dir.get().normalized();
160  float cost = map_ptr->costAtPosition(handles, bary_coords);
161  const mesh_map::Normal& mesh_normal = poseToDirectionVector(pose, tf2::Vector3(0,0,1));
162  std::array<float, 2> velocities = naiveControl(robot_pos, robot_dir, mesh_dir, mesh_normal, cost);
163  cmd_vel.twist.linear.x = std::min(config.max_lin_velocity, velocities[0] * config.lin_vel_factor);
164  cmd_vel.twist.angular.z = std::min(config.max_ang_velocity, velocities[1] * config.ang_vel_factor);
165  cmd_vel.header.stamp = ros::Time::now();
166 
167  if (cancel_requested)
168  {
169  return mbf_msgs::ExePathResult::CANCELED;
170  }
171  return mbf_msgs::ExePathResult::SUCCESS;
172 }
173 
174 bool MeshController::isGoalReached(double dist_tolerance, double angle_tolerance)
175 {
176  float goal_distance = (goal_pos - robot_pos).length();
177  float angle = acos(goal_dir.dot(robot_dir));
178  return goal_distance <= static_cast<float>(dist_tolerance) && angle <= static_cast<float>(angle_tolerance);
179 }
180 
181 bool MeshController::setPlan(const std::vector<geometry_msgs::PoseStamped>& plan)
182 {
183  // copy vector field // TODO just use vector field without copying
184  vector_map = map_ptr->getVectorMap();
185  DEBUG_CALL(map_ptr->publishDebugPoint(poseToPositionVector(plan.front()), mesh_map::color(0, 1, 0), "plan_start");)
186  DEBUG_CALL(map_ptr->publishDebugPoint(poseToPositionVector(plan.back()), mesh_map::color(1, 0, 0), "plan_goal");)
187  current_plan = plan;
190 
191  // reset current and ahead face
192  cancel_requested = false;
194  return true;
195 }
196 
198 {
199  ROS_INFO_STREAM("The MeshController has been requested to cancel!");
200  cancel_requested = true;
201  return true;
202 }
203 
204 mesh_map::Normal MeshController::poseToDirectionVector(const geometry_msgs::PoseStamped& pose, const tf2::Vector3& axis)
205 {
207  fromMsg(pose, transform);
208  tf2::Vector3 v = transform.getBasis() * axis;
209  return mesh_map::Normal(v.x(), v.y(), v.z());
210 }
211 
212 mesh_map::Vector MeshController::poseToPositionVector(const geometry_msgs::PoseStamped& pose)
213 {
214  return mesh_map::Vector(pose.pose.position.x, pose.pose.position.y, pose.pose.position.z);
215 }
216 
217 float MeshController::gaussValue(const float& sigma_squared, const float& value)
218 {
219  return exp(-value * value / 2 * sigma_squared) / sqrt(2 * M_PI * sigma_squared);
220 }
221 
222 std::array<float, 2> MeshController::naiveControl(
223  const mesh_map::Vector& robot_pos,
224  const mesh_map::Normal& robot_dir,
225  const mesh_map::Vector& mesh_dir,
226  const mesh_map::Normal& mesh_normal,
227  const float& mesh_cost)
228 {
229  float phi = acos(mesh_dir.dot(robot_dir));
230  float sign_phi = mesh_dir.cross(robot_dir).dot(mesh_normal);
231  // debug output angle between supposed and current angle
232  DEBUG_CALL(std_msgs::Float32 angle32; angle32.data = phi * 180 / M_PI; angle_pub.publish(angle32);)
233 
234  float angular_velocity = copysignf(phi * config.max_ang_velocity / M_PI, -sign_phi);
235  const float max_angle = config.max_angle * M_PI / 180.0;
236  const float max_linear = config.max_lin_velocity;
237  float linear_velocity = phi <= max_angle ? max_linear - (phi * max_linear / max_angle) : 0.0;
238  return { linear_velocity, angular_velocity };
239 }
240 
241 void MeshController::reconfigureCallback(mesh_controller::MeshControllerConfig& cfg, uint32_t level)
242 {
243  config = cfg;
244 }
245 
246 bool MeshController::initialize(const std::string& plugin_name, const boost::shared_ptr<tf2_ros::Buffer>& tf_ptr,
247  const boost::shared_ptr<mesh_map::MeshMap>& mesh_map_ptr)
248 {
249  ros::NodeHandle private_nh("~/" + plugin_name);
250  map_ptr = mesh_map_ptr;
252  new dynamic_reconfigure::Server<mesh_controller::MeshControllerConfig>(private_nh));
253 
254  config_callback = boost::bind(&MeshController::reconfigureCallback, this, _1, _2);
256  angle_pub = private_nh.advertise<std_msgs::Float32>("current_angle", 1);
257  return true;
258 }
259 } /* namespace mesh_controller */
mesh_controller::MeshController::robot_dir
mesh_map::Normal robot_dir
Definition: mesh_controller.h:168
mesh_controller::MeshController::config
MeshControllerConfig config
current mesh controller configuration
Definition: mesh_controller.h:183
mesh_controller::MeshController::goal_dir
mesh_map::Normal goal_dir
the goal's and robot's orientation
Definition: mesh_controller.h:168
mesh_controller::MeshController::reconfigureCallback
void reconfigureCallback(mesh_controller::MeshControllerConfig &cfg, uint32_t level)
reconfigure callback function which is called if a dynamic reconfiguration were triggered.
Definition: mesh_controller.cpp:241
DEBUG_CALL
#define DEBUG_CALL(method)
Definition: mesh_controller.cpp:54
Meap.hpp
mesh_controller::MeshController::vector_map
lvr2::DenseVertexMap< mesh_map::Vector > vector_map
The vector field to the goal.
Definition: mesh_controller.h:174
lvr2::BaseVector
transform
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
boost::shared_ptr
mesh_controller::MeshController::reconfigure_server_ptr
boost::shared_ptr< dynamic_reconfigure::Server< mesh_controller::MeshControllerConfig > > reconfigure_server_ptr
shared pointer to dynamic reconfigure server
Definition: mesh_controller.h:177
lvr2::FaceHandle
fromMsg
void fromMsg(const A &, B &b)
mesh_controller::MeshController::initialize
virtual bool initialize(const std::string &plugin_name, const boost::shared_ptr< tf2_ros::Buffer > &tf_ptr, const boost::shared_ptr< mesh_map::MeshMap > &mesh_map_ptr)
Initializes the controller plugin with a name, a tf pointer and a mesh map pointer.
Definition: mesh_controller.cpp:246
mesh_controller::MeshController::current_plan
vector< geometry_msgs::PoseStamped > current_plan
the current set plan
Definition: mesh_controller.h:162
mesh_map::color
std_msgs::ColorRGBA color(const float &r, const float &g, const float &b, const float &a=1.0)
tf2::Stamped
mesh_controller::MeshController::MeshController
MeshController()
Constructor.
Definition: mesh_controller.cpp:61
lvr2::BaseVector::cross
BaseVector< CoordT > cross(const BaseVector &other) const
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
BaseOptionalHandle< Index, FaceHandle >::unwrap
FaceHandle unwrap() const
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
mesh_controller::MeshController::naiveControl
std::array< float, 2 > naiveControl(const mesh_map::Vector &robot_pos, const mesh_map::Normal &robot_dir, const mesh_map::Vector &mesh_dir, const mesh_map::Normal &mesh_normal, const float &mesh_cost)
Definition: mesh_controller.cpp:222
mesh_map::Vector
lvr2::BaseVector< float > Vector
mesh_controller::MeshController::config_callback
dynamic_reconfigure::Server< mesh_controller::MeshControllerConfig >::CallbackType config_callback
dynamic reconfigure callback function binding
Definition: mesh_controller.h:180
mesh_controller::MeshController::map_ptr
boost::shared_ptr< mesh_map::MeshMap > map_ptr
shared pointer to the used mesh map
Definition: mesh_controller.h:159
class_list_macros.h
mesh_controller::MeshController::isGoalReached
virtual bool isGoalReached(double dist_tolerance, double angle_tolerance)
Checks if the robot reached to goal pose.
Definition: mesh_controller.cpp:174
M_PI
#define M_PI
lvr2::Normal< float >
mesh_controller::MeshController::gaussValue
float gaussValue(const float &sigma_squared, const float &value)
Definition: mesh_controller.cpp:217
lvr2::OptionalFaceHandle
mesh_controller::MeshController::~MeshController
virtual ~MeshController()
Destructor.
Definition: mesh_controller.cpp:65
angle
double angle(const geometry_msgs::PoseStamped &pose1, const geometry_msgs::PoseStamped &pose2)
mesh_controller::MeshController::poseToPositionVector
mesh_map::Vector poseToPositionVector(const geometry_msgs::PoseStamped &pose)
Definition: mesh_controller.cpp:212
mesh_controller::MeshController::poseToDirectionVector
mesh_map::Normal poseToDirectionVector(const geometry_msgs::PoseStamped &pose, const tf2::Vector3 &axis=tf2::Vector3(1, 0, 0))
Definition: mesh_controller.cpp:204
mesh_controller::MeshController::goal_pos
mesh_map::Vector goal_pos
the goal and robot pose
Definition: mesh_controller.h:165
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
exe_path_exception.h
mesh_controller::MeshController::cancel_requested
std::atomic_bool cancel_requested
flag to handle cancel requests
Definition: mesh_controller.h:189
mesh_controller::MeshController::setPlan
virtual bool setPlan(const std::vector< geometry_msgs::PoseStamped > &plan)
Sets the current plan to follow, it also sets the vector field.
Definition: mesh_controller.cpp:181
mesh_controller::MeshController::current_face
lvr2::OptionalFaceHandle current_face
The triangle on which the robot is located.
Definition: mesh_controller.h:171
mesh_map::linearCombineBarycentricCoords
T linearCombineBarycentricCoords(const std::array< lvr2::VertexHandle, 3 > &vertices, const lvr2::VertexMap< T > &attribute_map, const std::array< float, 3 > &barycentric_coords)
mesh_controller.h
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(mesh_controller::MeshController, mbf_mesh_core::MeshController)
mesh_controller
Definition: mesh_controller.h:44
mesh_controller::MeshController::robot_pos
mesh_map::Vector robot_pos
Definition: mesh_controller.h:165
mesh_controller::MeshController::angle_pub
ros::Publisher angle_pub
publishes the angle between the robots orientation and the goal vector field for debug purposes
Definition: mesh_controller.h:186
length
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
mbf_mesh_core::MeshController
mesh_controller::MeshController::cancel
virtual bool cancel()
Requests the planner to cancel, e.g. if it takes too much time.
Definition: mesh_controller.cpp:197
lvr2::BaseVector::dot
CoordT dot(const BaseVector &other) const
tf2_geometry_msgs.h
mesh_map::Normal
lvr2::Normal< float > Normal
mesh_map::projectedBarycentricCoords
bool projectedBarycentricCoords(const Vector &p, const std::array< Vector, 3 > &vertices, std::array< float, 3 > &barycentric_coords)
mesh_controller::MeshController::computeVelocityCommands
virtual uint32_t computeVelocityCommands(const geometry_msgs::PoseStamped &pose, const geometry_msgs::TwistStamped &velocity, geometry_msgs::TwistStamped &cmd_vel, std::string &message)
Given the current position, orientation, and velocity of the robot, compute the next velocity command...
Definition: mesh_controller.cpp:69
mesh
HalfEdgeMesh< Vec > mesh
mesh_controller::MeshController
Definition: mesh_controller.h:46
util.h
HalfEdgeMesh.hpp
ros::NodeHandle
ros::Time::now
static Time now()


mesh_controller
Author(s): Sebastian Pütz , Sabrina Frohn
autogenerated on Thu Jan 25 2024 03:43:00