hector_trajectory_server.cpp
Go to the documentation of this file.
1 //=================================================================================================
2 // Copyright (c) 2011, Stefan Kohlbrecher, TU Darmstadt
3 // All rights reserved.
4 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of the Simulation, Systems Optimization and Robotics
13 // group, TU Darmstadt nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without
15 // specific prior written permission.
16 
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //=================================================================================================
28 
29 #include <cstdio>
30 #include "ros/ros.h"
31 #include "ros/console.h"
32 
33 #include "nav_msgs/Path.h"
34 #include "std_msgs/String.h"
35 
36 #include <geometry_msgs/Quaternion.h>
37 #include <geometry_msgs/PoseStamped.h>
38 
39 #include "tf/transform_listener.h"
40 
41 #include <hector_nav_msgs/GetRobotTrajectory.h>
42 #include <hector_nav_msgs/GetRecoveryInfo.h>
43 
44 #include <tf/tf.h>
45 
46 #include <algorithm>
47 
48 using namespace std;
49 
50 bool comparePoseStampedStamps (const geometry_msgs::PoseStamped& t1, const geometry_msgs::PoseStamped& t2) { return (t1.header.stamp < t2.header.stamp); }
51 
52 
57 {
58 public:
60  {
61  ros::NodeHandle private_nh("~");
62 
63  private_nh.param("target_frame_name", p_target_frame_name_, std::string("map"));
64  private_nh.param("source_frame_name", p_source_frame_name_, std::string("base_link"));
65  private_nh.param("trajectory_update_rate", p_trajectory_update_rate_, 4.0);
66  private_nh.param("trajectory_publish_rate", p_trajectory_publish_rate_, 0.25);
67 
68  waitForTf();
69 
70  ros::NodeHandle nh;
71  sys_cmd_sub_ = nh.subscribe("syscommand", 1, &PathContainer::sysCmdCallback, this);
72  trajectory_pub_ = nh.advertise<nav_msgs::Path>("trajectory",1, true);
73 
74  trajectory_provider_service_ = nh.advertiseService("trajectory", &PathContainer::trajectoryProviderCallBack, this);
75  recovery_info_provider_service_ = nh.advertiseService("trajectory_recovery_info", &PathContainer::recoveryInfoProviderCallBack, this);
76 
77  last_reset_time_ = ros::Time::now();
78 
79  update_trajectory_timer_ = private_nh.createTimer(ros::Duration(1.0 / p_trajectory_update_rate_), &PathContainer::trajectoryUpdateTimerCallback, this, false);
80  publish_trajectory_timer_ = private_nh.createTimer(ros::Duration(1.0 / p_trajectory_publish_rate_), &PathContainer::publishTrajectoryTimerCallback, this, false);
81 
82  pose_source_.pose.orientation.w = 1.0;
83  pose_source_.header.frame_id = p_source_frame_name_;
84 
85  trajectory_.trajectory.header.frame_id = p_target_frame_name_;
86  }
87 
88  void waitForTf()
89  {
90  ros::Time start = ros::Time::now();
91  ROS_INFO("Waiting for tf transform data between frames %s and %s to become available", p_target_frame_name_.c_str(), p_source_frame_name_.c_str() );
92 
93  bool transform_successful = false;
94 
95  while (!transform_successful){
96  transform_successful = tf_.canTransform(p_target_frame_name_, p_source_frame_name_, ros::Time());
97  if (transform_successful) break;
98 
99  ros::Time now = ros::Time::now();
100 
101  if ((now-start).toSec() > 20.0){
102  ROS_WARN_ONCE("No transform between frames %s and %s available after %f seconds of waiting. This warning only prints once.", p_target_frame_name_.c_str(), p_source_frame_name_.c_str(), (now-start).toSec());
103  }
104 
105  if (!ros::ok()) return;
106  ros::WallDuration(1.0).sleep();
107  }
108 
109  ros::Time end = ros::Time::now();
110  ROS_INFO("Finished waiting for tf, waited %f seconds", (end-start).toSec());
111  }
112 
113 
114  void sysCmdCallback(const std_msgs::String& sys_cmd)
115  {
116  if (sys_cmd.data == "reset")
117  {
118  last_reset_time_ = ros::Time::now();
119  trajectory_.trajectory.poses.clear();
120  trajectory_.trajectory.header.stamp = ros::Time::now();
121  }
122  }
123 
125  {
126  pose_source_.header.stamp = ros::Time(0);
127 
128  geometry_msgs::PoseStamped pose_out;
129 
130  tf_.transformPose(p_target_frame_name_, pose_source_, pose_out);
131 
132  if (trajectory_.trajectory.poses.size() != 0){
133  //Only add pose to trajectory if it's not already stored
134  if (pose_out.header.stamp != trajectory_.trajectory.poses.back().header.stamp){
135  trajectory_.trajectory.poses.push_back(pose_out);
136  }
137  }else{
138  trajectory_.trajectory.poses.push_back(pose_out);
139  }
140 
141  trajectory_.trajectory.header.stamp = pose_out.header.stamp;
142  }
143 
145  {
146 
147  try{
148  addCurrentTfPoseToTrajectory();
149  }catch(tf::TransformException e)
150  {
151  ROS_WARN("Trajectory Server: Transform from %s to %s failed: %s \n", p_target_frame_name_.c_str(), pose_source_.header.frame_id.c_str(), e.what() );
152  }
153  }
154 
156  {
157  trajectory_pub_.publish(trajectory_.trajectory);
158  }
159 
160  bool trajectoryProviderCallBack(hector_nav_msgs::GetRobotTrajectory::Request &req,
161  hector_nav_msgs::GetRobotTrajectory::Response &res )
162  {
163  res = getTrajectory();
164  return true;
165  }
166 
167  inline const hector_nav_msgs::GetRobotTrajectoryResponse getTrajectory() const
168  {
169  return trajectory_;
170  }
171 
172  bool recoveryInfoProviderCallBack(hector_nav_msgs::GetRecoveryInfo::Request &req,
173  hector_nav_msgs::GetRecoveryInfo::Response &res )
174  {
175  const ros::Time req_time = req.request_time;
176 
177  geometry_msgs::PoseStamped tmp;
178  tmp.header.stamp = req_time;
179 
180  std::vector<geometry_msgs::PoseStamped> const & poses = trajectory_.trajectory.poses;
181 
182  if(poses.size() == 0)
183  {
184  ROS_WARN("Failed to find trajectory leading out of radius %f"
185  " because no poses, i.e. no inverse trajectory, exists.", req.request_radius);
186  return false;
187  }
188 
189  //Find the robot pose in the saved trajectory
190  std::vector<geometry_msgs::PoseStamped>::const_iterator it
191  = std::lower_bound(poses.begin(), poses.end(), tmp, comparePoseStampedStamps);
192 
193  //If we didn't find the robot pose for the desired time, add the current robot pose to trajectory
194  if (it == poses.end()){
195  addCurrentTfPoseToTrajectory();
196  it = poses.end();
197  --it;
198  }
199 
200  std::vector<geometry_msgs::PoseStamped>::const_iterator it_start = it;
201 
202  const geometry_msgs::Point& req_coords ((*it).pose.position);
203 
204  double dist_sqr_threshold = req.request_radius * req.request_radius;
205 
206  double dist_sqr = 0.0;
207 
208  //Iterate backwards till the start of the trajectory is reached or we find a pose that's outside the specified radius
209  while (it != poses.begin() && dist_sqr < dist_sqr_threshold){
210  const geometry_msgs::Point& curr_coords ((*it).pose.position);
211 
212  dist_sqr = (req_coords.x - curr_coords.x) * (req_coords.x - curr_coords.x) +
213  (req_coords.y - curr_coords.y) * (req_coords.y - curr_coords.y);
214 
215  --it;
216  }
217 
218  if (dist_sqr < dist_sqr_threshold){
219  ROS_INFO("Failed to find trajectory leading out of radius %f", req.request_radius);
220  return false;
221  }
222 
223  std::vector<geometry_msgs::PoseStamped>::const_iterator it_end = it;
224 
225  res.req_pose = *it_start;
226  res.radius_entry_pose = *it_end;
227 
228  std::vector<geometry_msgs::PoseStamped>& traj_out_poses = res.trajectory_radius_entry_pose_to_req_pose.poses;
229 
230  res.trajectory_radius_entry_pose_to_req_pose.poses.clear();
231  res.trajectory_radius_entry_pose_to_req_pose.header = res.req_pose.header;
232 
233  for (std::vector<geometry_msgs::PoseStamped>::const_iterator it_tmp = it_start; it_tmp != it_end; --it_tmp){
234  traj_out_poses.push_back(*it_tmp);
235  }
236 
237  return true;
238  }
239 
240  //parameters
241  std::string p_target_frame_name_;
242  std::string p_source_frame_name_;
245 
246  // Zero pose used for transformation to target_frame.
247  geometry_msgs::PoseStamped pose_source_;
248 
251 
254 
255 
256  //ros::Subscriber pose_update_sub_;
259 
260  hector_nav_msgs::GetRobotTrajectory::Response trajectory_;
261 
263 
266 };
267 
268 int main(int argc, char** argv)
269 {
270  ros::init(argc, argv, "hector_trajectory_server");
271 
272  PathContainer pc;
273 
274  ros::spin();
275 
276  return 0;
277 }
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
int main(int argc, char **argv)
const hector_nav_msgs::GetRobotTrajectoryResponse getTrajectory() const
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
void sysCmdCallback(const std_msgs::String &sys_cmd)
#define ROS_WARN(...)
ROSCPP_DECL void spin(Spinner &spinner)
bool sleep() const
bool trajectoryProviderCallBack(hector_nav_msgs::GetRobotTrajectory::Request &req, hector_nav_msgs::GetRobotTrajectory::Response &res)
#define ROS_WARN_ONCE(...)
#define ROS_INFO(...)
void publishTrajectoryTimerCallback(const ros::TimerEvent &event)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
tf::TransformListener tf_
void trajectoryUpdateTimerCallback(const ros::TimerEvent &event)
ROSCPP_DECL bool ok()
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool comparePoseStampedStamps(const geometry_msgs::PoseStamped &t1, const geometry_msgs::PoseStamped &t2)
ros::Timer publish_trajectory_timer_
ros::ServiceServer trajectory_provider_service_
Map generation node.
hector_nav_msgs::GetRobotTrajectory::Response trajectory_
static Time now()
bool recoveryInfoProviderCallBack(hector_nav_msgs::GetRecoveryInfo::Request &req, hector_nav_msgs::GetRecoveryInfo::Response &res)
ros::Subscriber sys_cmd_sub_
ros::Publisher trajectory_pub_
geometry_msgs::PoseStamped pose_source_
ros::ServiceServer recovery_info_provider_service_


hector_trajectory_server
Author(s): Stefan Kohlbrecher
autogenerated on Sun Nov 3 2019 03:18:42