laser_ortho_projector.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, 2011, Ivan Dryanovski, William Morris
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  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the CCNY Robotics Lab nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
31 
33 
34 namespace scan_tools {
35 
37  nh_(nh),
38  nh_private_(nh_private)
39 {
40  ROS_INFO ("Starting LaserOrthoProjector");
41 
42  initialized_ = false;
43 
44  // set initial orientation to 0
45 
47 
48  nan_point_.x = std::numeric_limits<float>::quiet_NaN();
49  nan_point_.y = std::numeric_limits<float>::quiet_NaN();
50  nan_point_.z = std::numeric_limits<float>::quiet_NaN();
51 
52  // **** parameters
53 
54  if (!nh_private_.getParam ("fixed_frame", world_frame_))
55  world_frame_ = "/world";
56  if (!nh_private_.getParam ("base_frame", base_frame_))
57  base_frame_ = "/base_link";
58  if (!nh_private_.getParam ("ortho_frame", ortho_frame_))
59  ortho_frame_ = "/base_ortho";
60  if (!nh_private_.getParam ("publish_tf", publish_tf_))
61  publish_tf_ = false;
62  if (!nh_private_.getParam ("use_pose", use_pose_))
63  use_pose_ = true;
64  if (!nh_private_.getParam ("use_imu", use_imu_))
65  use_imu_ = false;
66 
67  if (use_imu_ && use_pose_)
68  ROS_FATAL("use_imu and use_pose params cannot both be true");
69  if (!use_imu_ && !use_pose_)
70  ROS_FATAL("use_imu and use_pose params cannot both be false");
71 
72 
73  // **** subscribe to laser scan messages
74 
76  "scan", 10, &LaserOrthoProjector::scanCallback, this);
77 
78  if (use_pose_)
79  {
81  "pose", 10, &LaserOrthoProjector::poseCallback, this);
82  }
83  if (use_imu_)
84  {
86  "imu/data", 10, &LaserOrthoProjector::imuCallback, this);
87  }
88 
89  // **** advertise orthogonal scan
90 
92  "cloud_ortho", 10);
93 }
94 
96 {
97 
98 }
99 
100 void LaserOrthoProjector::imuCallback(const ImuMsg::ConstPtr& imu_msg)
101 {
102  // obtain world to base frame transform from the pose message
103  tf::Transform world_to_base;
104  world_to_base.setIdentity();
105 
106  tf::Quaternion q;
107  tf::quaternionMsgToTF(imu_msg->orientation, q);
108  world_to_base.setRotation(q);
109 
110  // calculate world to ortho frame transform
111  tf::Transform world_to_ortho;
112  getOrthoTf(world_to_base, world_to_ortho);
113 
114  if (publish_tf_)
115  {
116  tf::StampedTransform world_to_ortho_tf(
117  world_to_ortho, imu_msg->header.stamp, world_frame_, ortho_frame_);
118  tf_broadcaster_.sendTransform(world_to_ortho_tf);
119  }
120 
121  // calculate ortho to laser tf, and save it for when scans arrive
122  ortho_to_laser_ = world_to_ortho.inverse() * world_to_base * base_to_laser_;
123 }
124 
125 void LaserOrthoProjector::poseCallback(const PoseMsg::ConstPtr& pose_msg)
126 {
127  // obtain world to base frame transform from the pose message
128  tf::Transform world_to_base;
129  tf::poseMsgToTF(pose_msg->pose, world_to_base);
130 
131  // calculate world to ortho frame transform
132  tf::Transform world_to_ortho;
133  getOrthoTf(world_to_base, world_to_ortho);
134 
135  if (publish_tf_)
136  {
137  tf::StampedTransform world_to_ortho_tf(
138  world_to_ortho, pose_msg->header.stamp, world_frame_, ortho_frame_);
139  tf_broadcaster_.sendTransform(world_to_ortho_tf);
140  }
141 
142  // calculate ortho to laser tf, and save it for when scans arrive
143  ortho_to_laser_ = world_to_ortho.inverse() * world_to_base * base_to_laser_;
144 }
145 
146 void LaserOrthoProjector::getOrthoTf(const tf::Transform& world_to_base, tf::Transform& world_to_ortho)
147 {
148  const tf::Vector3& w2b_o = world_to_base.getOrigin();
149  const tf::Quaternion& w2b_q = world_to_base.getRotation();
150 
151  tf::Vector3 wto_o(w2b_o.getX(), w2b_o.getY(), 0.0);
153 
154  world_to_ortho.setOrigin(wto_o);
155  world_to_ortho.setRotation(wto_q);
156 }
157 
158 void LaserOrthoProjector::scanCallback(const sensor_msgs::LaserScan::ConstPtr& scan_msg)
159 {
160  if(!initialized_)
161  {
162  initialized_ = getBaseToLaserTf(scan_msg);
163 
164  if (initialized_) createCache(scan_msg);
165  else return;
166  }
167 
168  if(!use_pose_)
169  {
170  // obtain transform between fixed and base frame
171  tf::StampedTransform world_to_base_tf;
172  try
173  {
175  world_frame_, base_frame_, scan_msg->header.stamp, ros::Duration(0.1));
177  world_frame_, base_frame_, scan_msg->header.stamp, world_to_base_tf);
178  }
179  catch (tf::TransformException ex)
180  {
181  // transform unavailable - skip scan
182  ROS_WARN("Skipping scan %s", ex.what());
183  return;
184  }
185 
186  // calculate world to ortho frame transform
187  tf::Transform world_to_ortho;
188  getOrthoTf(world_to_base_tf, world_to_ortho);
189  }
190 
191  // **** build and publish projected cloud
192 
193  PointCloudT::Ptr cloud =
195 
196  pcl_conversions::toPCL(scan_msg->header, cloud->header);
197  cloud->header.frame_id = ortho_frame_;
198 
199  for (unsigned int i = 0; i < scan_msg->ranges.size(); i++)
200  {
201  double r = scan_msg->ranges[i];
202 
203  if (r > scan_msg->range_min)
204  {
205  tf::Vector3 p(r * a_cos_[i], r * a_sin_[i], 0.0);
206  p = ortho_to_laser_ * p;
207 
208  PointT point;
209  point.x = p.getX();
210  point.y = p.getY();
211  point.z = 0.0;
212  cloud->points.push_back(point);
213  }
214  }
215 
216  cloud->width = cloud->points.size();
217  cloud->height = 1;
218  cloud->is_dense = true; // no nan's present
219 
220  cloud_publisher_.publish (cloud);
221 }
222 
223 bool LaserOrthoProjector::getBaseToLaserTf (const sensor_msgs::LaserScan::ConstPtr& scan_msg)
224 {
225  tf::StampedTransform base_to_laser_tf;
226  try
227  {
229  base_frame_, scan_msg->header.frame_id, scan_msg->header.stamp, ros::Duration(1.0));
231  base_frame_, scan_msg->header.frame_id, scan_msg->header.stamp, base_to_laser_tf);
232  }
233  catch (tf::TransformException ex)
234  {
235  ROS_WARN("LaserOrthoProjector: Could not get initial laser transform(%s)", ex.what());
236  return false;
237  }
238  base_to_laser_ = base_to_laser_tf;
239 
240  return true;
241 }
242 
243 void LaserOrthoProjector::createCache (const sensor_msgs::LaserScan::ConstPtr& scan_msg)
244 {
245  a_cos_.clear();
246  a_sin_.clear();
247 
248  for (unsigned int i = 0; i < scan_msg->ranges.size(); ++i)
249  {
250  double angle = scan_msg->angle_min + i * scan_msg->angle_increment;
251  a_cos_.push_back(cos(angle));
252  a_sin_.push_back(sin(angle));
253  }
254 }
255 
256 } //namespace scan_tools
bool getBaseToLaserTf(const sensor_msgs::LaserScan::ConstPtr &scan_msg)
TFSIMD_FORCE_INLINE void setRotation(const Quaternion &q)
static void poseMsgToTF(const geometry_msgs::Pose &msg, Pose &bt)
#define ROS_FATAL(...)
void publish(const boost::shared_ptr< M > &message) const
pcl::PointCloud< PointT > PointCloudT
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
static double getYaw(const Quaternion &bt_q)
void scanCallback(const sensor_msgs::LaserScan::ConstPtr &scan_msg)
TFSIMD_FORCE_INLINE const tfScalar & getY() const
void getOrthoTf(const tf::Transform &world_to_base, tf::Transform &world_to_ortho)
#define ROS_WARN(...)
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
void setIdentity()
bool waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
tf::TransformBroadcaster tf_broadcaster_
TFSIMD_FORCE_INLINE const tfScalar & x() const
static Quaternion createQuaternionFromYaw(double yaw)
static void quaternionMsgToTF(const geometry_msgs::Quaternion &msg, Quaternion &bt)
#define ROS_INFO(...)
LaserOrthoProjector(ros::NodeHandle nh, ros::NodeHandle nh_private)
void sendTransform(const StampedTransform &transform)
Transform inverse() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
void createCache(const sensor_msgs::LaserScan::ConstPtr &scan_msg)
void imuCallback(const ImuMsg::ConstPtr &imu_msg)
Quaternion getRotation() const
bool getParam(const std::string &key, std::string &s) const
TFSIMD_FORCE_INLINE const tfScalar & getX() const
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)
void poseCallback(const PoseMsg::ConstPtr &pose_msg)


laser_ortho_projector
Author(s): Ivan Dryanovski, William Morris
autogenerated on Mon Jun 10 2019 15:08:37