hinted_handle_estimator_nodelet.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2015, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 #define BOOST_PARAMETER_MAX_ARITY 7
39 #include <pcl/features/normal_3d.h>
40 #include <pcl/kdtree/kdtree_flann.h>
41 #include <pcl/common/transforms.h>
42 #include <pcl/filters/passthrough.h>
45 #include <tf/tf.h>
46 #include <math.h>
47 
48 using namespace std;
49 
50 inline float NORM(float vx, float vy, float vz){return sqrt(vx*vx+vy*vy+vz*vz);}
51 
52 namespace jsk_pcl_ros
53 {
54  void HintedHandleEstimator::onInit()
55  {
56  DiagnosticNodelet::onInit();
57  pub_pose_ = advertise<geometry_msgs::PoseStamped>(
58  *pnh_, "handle_pose", 1);
59  pub_length_ = advertise<std_msgs::Float64>(
60  *pnh_, "handle_length", 1);
61  pub_handle_ = advertise<jsk_recognition_msgs::SimpleHandle>(
62  *pnh_, "handle", 1);
63  pub_debug_marker_ = advertise<visualization_msgs::Marker>(*pnh_, "debug_marker", 1);
64  pub_debug_marker_array_ = advertise<visualization_msgs::MarkerArray>(*pnh_, "debug_marker_array", 1);
65  handle = handle_model();
66  pnh_->param("finger_l", handle.finger_l, 0.03);
67  pnh_->param("finger_d", handle.finger_d, 0.02);
68  pnh_->param("finger_w", handle.finger_w, 0.01);
69  pnh_->param("arm_l", handle.arm_l, 0.05);
70  pnh_->param("arm_d", handle.arm_d, 0.02);
71  pnh_->param("arm_w", handle.arm_w, 0.1);
72  onInitPostProcess();
73  }
74 
75  HintedHandleEstimator::~HintedHandleEstimator() {
76  // message_filters::Synchronizer needs to be called reset
77  // before message_filters::Subscriber is freed.
78  // Calling reset fixes the following error on shutdown of the nodelet:
79  // terminate called after throwing an instance of
80  // 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
81  // what(): boost: mutex lock failed in pthread_mutex_lock: Invalid argument
82  // Also see https://github.com/ros/ros_comm/issues/720 .
83  sync_.reset();
84  }
85 
86  void HintedHandleEstimator::subscribe()
87  {
88  sub_cloud_.subscribe(*pnh_, "cloud", 1);
89  sub_point_.subscribe(*pnh_, "point", 1);
90  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
91  sync_->connectInput(sub_cloud_, sub_point_);
92  sync_->registerCallback(boost::bind(&HintedHandleEstimator::estimate, this, _1, _2));
93  }
94 
95  void HintedHandleEstimator::unsubscribe()
96  {
97  sub_cloud_.unsubscribe();
98  sub_point_.unsubscribe();
99  }
100 
101  void HintedHandleEstimator::estimate(
102  const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
103  const geometry_msgs::PointStampedConstPtr &point_msg)
104  {
105  boost::mutex::scoped_lock lock(mutex_);
106  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
107  pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
108  pcl::PassThrough<pcl::PointXYZ> pass;
109  int K = 1;
110  std::vector<int> pointIdxNKNSearch(K);
111  std::vector<float> pointNKNSquaredDistance(K);
112  pcl::search::KdTree<pcl::PointXYZ>::Ptr kd_tree(new pcl::search::KdTree<pcl::PointXYZ>);
113 
114  pcl::fromROSMsg(*cloud_msg, *cloud);
115  geometry_msgs::PointStamped transed_point;
117  try
118  {
119  listener_.waitForTransform(cloud->header.frame_id, point_msg->header.frame_id, now, ros::Duration(1.0));
120  listener_.transformPoint(cloud->header.frame_id, now, *point_msg, point_msg->header.frame_id, transed_point);
121  }
123  {
124  ROS_ERROR("%s", ex.what());
125  return;
126  }
127  pcl::PointXYZ searchPoint;
128  searchPoint.x = transed_point.point.x;
129  searchPoint.y = transed_point.point.y;
130  searchPoint.z = transed_point.point.z;
131 
132  //remove too far cloud
133  pass.setInputCloud(cloud);
134  pass.setFilterFieldName("x");
135  pass.setFilterLimits(searchPoint.x - 3*handle.arm_w, searchPoint.x + 3*handle.arm_w);
136  pass.filter(*cloud);
137  pass.setInputCloud(cloud);
138  pass.setFilterFieldName("y");
139  pass.setFilterLimits(searchPoint.y - 3*handle.arm_w, searchPoint.y + 3*handle.arm_w);
140  pass.filter(*cloud);
141  pass.setInputCloud(cloud);
142  pass.setFilterFieldName("z");
143  pass.setFilterLimits(searchPoint.z - 3*handle.arm_w, searchPoint.z + 3*handle.arm_w);
144  pass.filter(*cloud);
145 
146  if(cloud->points.size() < 10){
147  ROS_INFO("points are too small");
148  return;
149  }
150  if(1){ //estimate_normal
151  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
152  ne.setInputCloud(cloud);
153  ne.setSearchMethod(kd_tree);
154  ne.setRadiusSearch(0.02);
155  ne.setViewPoint(0, 0, 0);
156  ne.compute(*cloud_normals);
157  }
158  else{ //use normal of msg
159 
160  }
161  if(! (kd_tree->nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)){
162  ROS_INFO("kdtree failed");
163  return;
164  }
165  float x = cloud->points[pointIdxNKNSearch[0]].x;
166  float y = cloud->points[pointIdxNKNSearch[0]].y;
167  float z = cloud->points[pointIdxNKNSearch[0]].z;
168  float v_x = cloud_normals->points[pointIdxNKNSearch[0]].normal_x;
169  float v_y = cloud_normals->points[pointIdxNKNSearch[0]].normal_y;
170  float v_z = cloud_normals->points[pointIdxNKNSearch[0]].normal_z;
171  double theta = acos(v_x);
172  // use normal for estimating handle direction
173  tf::Quaternion normal(0, v_z/NORM(0, v_y, v_z) * cos(theta/2), -v_y/NORM(0, v_y, v_z) * cos(theta/2), sin(theta/2));
174  tf::Quaternion final_quaternion = normal;
175  double min_theta_index = 0;
176  double min_width = 100;
177  tf::Quaternion min_qua(0, 0, 0, 1);
178  visualization_msgs::Marker debug_hand_marker;
179  debug_hand_marker.header = cloud_msg->header;
180  debug_hand_marker.ns = string("debug_grasp");
181  debug_hand_marker.id = 0;
182  debug_hand_marker.type = visualization_msgs::Marker::LINE_LIST;
183  debug_hand_marker.pose.orientation.w = 1;
184  debug_hand_marker.scale.x=0.003;
185  tf::Matrix3x3 best_mat;
186  //search 180 degree and calc the shortest direction
187  for(double theta_=0; theta_<3.14/2;
188  theta_+=3.14/2/30){
189  tf::Quaternion rotate_(sin(theta_), 0, 0, cos(theta_));
190  tf::Quaternion temp_qua = normal * rotate_;
191  tf::Matrix3x3 temp_mat(temp_qua);
192  geometry_msgs::Pose pose_respected_to_tf;
193  pose_respected_to_tf.position.x = x;
194  pose_respected_to_tf.position.y = y;
195  pose_respected_to_tf.position.z = z;
196  pose_respected_to_tf.orientation.x = temp_qua.getX();
197  pose_respected_to_tf.orientation.y = temp_qua.getY();
198  pose_respected_to_tf.orientation.z = temp_qua.getZ();
199  pose_respected_to_tf.orientation.w = temp_qua.getW();
200  Eigen::Affine3d box_pose_respected_to_cloud_eigend;
201  tf::poseMsgToEigen(pose_respected_to_tf, box_pose_respected_to_cloud_eigend);
202  Eigen::Affine3d box_pose_respected_to_cloud_eigend_inversed
203  = box_pose_respected_to_cloud_eigend.inverse();
204  Eigen::Matrix4f box_pose_respected_to_cloud_eigen_inversed_matrixf;
205  Eigen::Matrix4d box_pose_respected_to_cloud_eigen_inversed_matrixd
206  = box_pose_respected_to_cloud_eigend_inversed.matrix();
207  jsk_recognition_utils::convertMatrix4<Eigen::Matrix4d, Eigen::Matrix4f>(
208  box_pose_respected_to_cloud_eigen_inversed_matrixd,
209  box_pose_respected_to_cloud_eigen_inversed_matrixf);
210  Eigen::Affine3f offset = Eigen::Affine3f(box_pose_respected_to_cloud_eigen_inversed_matrixf);
211  pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud(new pcl::PointCloud<pcl::PointXYZ>);
212  pcl::transformPointCloud(*cloud, *output_cloud, offset);
213 
214  pcl::PassThrough<pcl::PointXYZ> pass;
215  pcl::PointCloud<pcl::PointXYZ>::Ptr points_z(new pcl::PointCloud<pcl::PointXYZ>), points_yz(new pcl::PointCloud<pcl::PointXYZ>), points_xyz(new pcl::PointCloud<pcl::PointXYZ>);
216  pass.setInputCloud(output_cloud);
217  pass.setFilterFieldName("y");
218  pass.setFilterLimits(-handle.arm_w*2, handle.arm_w*2);
219  pass.filter(*points_z);
220  pass.setInputCloud(points_z);
221  pass.setFilterFieldName("z");
222  pass.setFilterLimits(-handle.finger_d, handle.finger_d);
223  pass.filter(*points_yz);
224  pass.setInputCloud(points_yz);
225  pass.setFilterFieldName("x");
226  pass.setFilterLimits(-(handle.arm_l-handle.finger_l), handle.finger_l);
227  pass.filter(*points_xyz);
228  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
229  for(size_t index=0; index<points_xyz->size(); index++){
230  points_xyz->points[index].x = points_xyz->points[index].z = 0;
231  }
232  if(points_xyz->points.size() == 0){ROS_INFO("points are empty");return;}
233  kdtree.setInputCloud(points_xyz);
234  std::vector<int> pointIdxRadiusSearch;
235  std::vector<float> pointRadiusSquaredDistance;
236  pcl::PointXYZ search_point_tree;
237  search_point_tree.x=search_point_tree.y=search_point_tree.z=0;
238  if( kdtree.radiusSearch(search_point_tree, 10, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 ){
239  double before_w=10, temp_w;
240  for(size_t index = 0; index < pointIdxRadiusSearch.size(); ++index){
241  temp_w =sqrt(pointRadiusSquaredDistance[index]);
242  if(temp_w - before_w > handle.finger_w*2){
243  break; // there are small space for finger
244  }
245  before_w=temp_w;
246  }
247  if(before_w < min_width){
248  min_theta_index = theta_;
249  min_width = before_w;
250  min_qua = temp_qua;
251  best_mat = temp_mat;
252  }
253  //for debug view
254  geometry_msgs::Point temp_point;
255  std_msgs::ColorRGBA temp_color;
256  temp_color.r=0; temp_color.g=0; temp_color.b=1; temp_color.a=1;
257  temp_point.x=x-temp_mat.getColumn(1)[0] * before_w;
258  temp_point.y=y-temp_mat.getColumn(1)[1] * before_w;
259  temp_point.z=z-temp_mat.getColumn(1)[2] * before_w;
260  debug_hand_marker.points.push_back(temp_point);
261  debug_hand_marker.colors.push_back(temp_color);
262  temp_point.x+=2*temp_mat.getColumn(1)[0] * before_w;
263  temp_point.y+=2*temp_mat.getColumn(1)[1] * before_w;
264  temp_point.z+=2*temp_mat.getColumn(1)[2] * before_w;
265  debug_hand_marker.points.push_back(temp_point);
266  debug_hand_marker.colors.push_back(temp_color);
267  }
268  }
269  geometry_msgs::PoseStamped handle_pose_stamped;
270  handle_pose_stamped.header = cloud_msg->header;
271  handle_pose_stamped.pose.position.x = x;
272  handle_pose_stamped.pose.position.y = y;
273  handle_pose_stamped.pose.position.z = z;
274  handle_pose_stamped.pose.orientation.x = min_qua.getX();
275  handle_pose_stamped.pose.orientation.y = min_qua.getY();
276  handle_pose_stamped.pose.orientation.z = min_qua.getZ();
277  handle_pose_stamped.pose.orientation.w = min_qua.getW();
278  std_msgs::Float64 min_width_msg;
279  min_width_msg.data = min_width;
280  pub_pose_.publish(handle_pose_stamped);
281  pub_debug_marker_.publish(debug_hand_marker);
282  pub_debug_marker_array_.publish(make_handle_array(handle_pose_stamped, handle));
283  jsk_recognition_msgs::SimpleHandle simple_handle;
284  simple_handle.header = handle_pose_stamped.header;
285  simple_handle.pose = handle_pose_stamped.pose;
286  simple_handle.handle_width = min_width;
287  pub_handle_.publish(simple_handle);
288  }
289 }
290 
293 
294 
tf::poseMsgToEigen
void poseMsgToEigen(const geometry_msgs::Pose &m, Eigen::Affine3d &e)
tf::Matrix3x3
extract_top_polygon_likelihood.ex
ex
Definition: extract_top_polygon_likelihood.py:51
hinted_handle_estimator.h
depth_error_calibration.lock
lock
Definition: depth_error_calibration.py:32
_2
boost::arg< 2 > _2
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::HintedHandleEstimator, nodelet::Nodelet)
string
K
K
handle_model
Definition: hinted_handle_estimator.h:58
theta
int theta
attention_pose_set.x
x
Definition: attention_pose_set.py:18
pcl::fromROSMsg
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
sin
double sin()
cloud
cloud
mutex_
boost::mutex mutex_
class_list_macros.h
jsk_pcl_ros
Definition: add_color_from_image.h:51
tf::Matrix3x3::getColumn
TFSIMD_FORCE_INLINE Vector3 getColumn(int i) const
jsk_pcl_ros::HintedHandleEstimator
Definition: hinted_handle_estimator.h:130
eigen_msg.h
ROS_ERROR
#define ROS_ERROR(...)
math.h
_1
boost::arg< 1 > _1
make_handle_array
visualization_msgs::MarkerArray make_handle_array(geometry_msgs::PoseStamped pose, handle_model handle)
Definition: hinted_handle_estimator.h:105
tf::Quaternion::getW
const TFSIMD_FORCE_INLINE tfScalar & getW() const
pcl_conversion_util.h
tf.h
nodelet::Nodelet
ros::Time
sqrt
double sqrt()
std
pub_pose_
ros::Publisher pub_pose_
cos
double cos()
index
unsigned int index
NORM
float NORM(float vx, float vy, float vz)
Definition: hinted_handle_estimator_nodelet.cpp:50
attention_pose_set.y
y
Definition: attention_pose_set.py:19
sample_snapit_pose_publisher.now
now
Definition: sample_snapit_pose_publisher.py:15
tf2::TransformException
ROS_INFO
#define ROS_INFO(...)
ros::Duration
tf::Quaternion
attention_pose_set.z
z
Definition: attention_pose_set.py:20
ros::Time::now
static Time now()


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Tue Jan 7 2025 04:05:44