45 #include <object_recognition_msgs/TableArray.h> 46 #include <object_recognition_msgs/RecognizedObjectArray.h> 47 #include <object_recognition_msgs/GetObjectInformation.h> 48 #include <object_recognition_msgs/ObjectRecognitionAction.h> 52 #include <turtlebot_arm_object_manipulation/ObjectDetectionAction.h> 55 #include <moveit_msgs/ObjectColor.h> 56 #include <moveit_msgs/PlanningScene.h> 80 turtlebot_arm_object_manipulation::ObjectDetectionFeedback
feedback_;
81 turtlebot_arm_object_manipulation::ObjectDetectionResult
result_;
82 turtlebot_arm_object_manipulation::ObjectDetectionGoalConstPtr
goal_;
87 std::map<std::string, object_recognition_msgs::ObjectInformation>
objs_info_;
122 pnh_(
"~"), ork_ac_(
"tabletop/recognize_objects", true), od_as_(name, false), action_name_(name),
123 ork_execute_timeout_(5.0), ork_preempt_timeout_(1.0)
128 ROS_INFO(
"[object detection] Waiting for tabletop/recognize_objects action server to start...");
131 ROS_ERROR(
"[object detection] tabletop/recognize_objects action server not available after 1 minute");
132 ROS_ERROR(
"[object detection] Shutting down node...");
136 ROS_INFO(
"[object detection] tabletop/recognize_objects action server started; ready for sending goals.");
139 obj_info_srv_ = nh_.
serviceClient<object_recognition_msgs::GetObjectInformation>(
"get_object_info");
142 ROS_ERROR(
"[object detection] Get object information service not available after 1 minute");
143 ROS_ERROR(
"[object detection] Shutting down node...");
158 nh_.
advertise<object_recognition_msgs::RecognizedObjectArray>(
"/tabletop/recognized_object_array", 1,
true);
160 nh_.
advertise<object_recognition_msgs::TableArray>(
"/tabletop/table_array", 1,
true);
165 ROS_INFO(
"[object detection] Received goal!");
170 arm_link_ = goal_->frame;
173 table_poses_.clear();
174 table_params_.clear();
175 result_.obj_names.clear();
182 std::vector<DetectionBin> detection_bins;
184 ROS_INFO(
"[object detection] Sending %d goals to tabletop/recognize_objects action server...",
185 CALLS_TO_ORK_TABLETOP);
186 object_recognition_msgs::ObjectRecognitionGoal goal;
190 ork_ac_.
sendGoalAndWait(goal, ork_execute_timeout_, ork_preempt_timeout_);
194 ROS_INFO(
"[object detection] Action successfully finished");
198 ROS_WARN(
"[object detection] Tabletop/recognize_objects action did not finish before the time out: %s",
200 od_as_.
setAborted(result_,
"Tabletop/recognize_objects action did not finish before the time out");
204 object_recognition_msgs::ObjectRecognitionResultConstPtr result = ork_ac_.
getResult();
207 for (
const object_recognition_msgs::RecognizedObject& obj: result->recognized_objects.objects)
209 if (obj.confidence < CONFIDENCE_THRESHOLD)
212 bool assigned =
false;
215 if (
mtk::distance3D(bin.getCentroid().pose, obj.pose.pose.pose) <= CLUSTERING_THRESHOLD)
217 ROS_DEBUG(
"Object with pose [%s] added to bin %d with centroid [%s] with distance [%f]",
231 new_bin.
id = detection_bins.size();
232 new_bin.addObject(obj);
233 detection_bins.push_back(new_bin);
241 int added_objects =
addObjects(detection_bins);
242 if (added_objects > 0)
244 ROS_INFO(
"[object detection] Succeeded! %d objects detected", added_objects);
247 if (table_poses_.size() > 0)
248 addTable(table_poses_, table_params_);
250 ROS_WARN(
"[object detection] No near-horizontal table detected!");
254 object_recognition_msgs::RecognizedObjectArray roa;
255 object_recognition_msgs::TableArray ta;
265 ROS_INFO(
"[object detection] Succeeded, but couldn't find any object");
273 ROS_WARN(
"[object detection] %s: Preempted", action_name_.c_str());
278 void tableCb(
const object_recognition_msgs::TableArray& msg)
280 if (msg.tables.size() == 0)
282 ROS_WARN(
"[object detection] Table array message is empty");
289 object_recognition_msgs::Table table = msg.tables[0];
290 geometry_msgs::Pose table_pose = table.pose;
292 if (std::isnan(table.pose.orientation.x) ||
293 std::isnan(table.pose.orientation.y) ||
294 std::isnan(table.pose.orientation.z) ||
295 std::isnan(table.pose.orientation.w))
297 ROS_WARN(
"[object detection] Table discarded as its orientation has nan values");
301 if (!
transformPose(msg.header.frame_id, arm_link_, table.pose, table_pose))
309 table_poses_.push_back(table_pose);
314 ROS_WARN(
"[object detection] Table with pose [%s] discarded: %.2f radians away from the horizontal",
323 int addObjects(
const std::vector<DetectionBin>& detection_bins)
325 std::map<std::string, unsigned int> obj_name_occurences;
326 std::vector<moveit_msgs::CollisionObject> collision_objects;
327 moveit_msgs::PlanningScene ps;
334 if (bin.countObjects() < CALLS_TO_ORK_TABLETOP/1.5)
336 ROS_DEBUG(
"Bin %d with centroid [%s] discarded as it received %d objects out of %d attempts",
344 object_recognition_msgs::ObjectInformation obj_info =
getObjInfo(bin.getType());
345 obj_name_occurences[obj_info.name]++;
346 std::stringstream sstream;
347 sstream << obj_info.name <<
" [" << obj_name_occurences[obj_info.name] <<
"]";
348 std::string
obj_name = sstream.str();
350 ROS_DEBUG(
"Bin %d with centroid [%s] and %d objects added as object '%s'",
351 bin.id,
mtk::pose2str3D(bin.getCentroid()).c_str(), bin.countObjects(), obj_name.c_str());
353 geometry_msgs::Pose out_pose;
355 ROS_INFO(
"[object detection] Adding '%s' object at %s",
358 result_.obj_names.push_back(obj_name);
360 moveit_msgs::CollisionObject co;
363 co.operation = moveit_msgs::CollisionObject::ADD;
365 if (obj_name.find(
"cube 2.5") != std::string::npos)
369 co.primitives.resize(1);
370 co.primitives[0].type = shape_msgs::SolidPrimitive::BOX;
371 co.primitives[0].dimensions.resize(3);
372 co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_X] = 0.025;
373 co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_Y] = 0.025;
374 co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_Z] = 0.025;
375 out_pose.position.z += 0.0125;
376 co.primitive_poses.push_back(out_pose);
380 co.meshes.resize(1, obj_info.ground_truth_mesh);
381 co.mesh_poses.push_back(out_pose);
384 collision_objects.push_back(co);
387 moveit_msgs::ObjectColor oc;
390 ps.object_colors.push_back(oc);
398 if (collision_objects.size() > 0)
403 return collision_objects.size();
406 void addTable(
const std::vector<geometry_msgs::Pose>& table_poses,
407 const std::vector<TableDescriptor>& table_params)
412 std::vector<double> table_center_x;
413 std::vector<double> table_center_y;
414 std::vector<double> table_size_x;
415 std::vector<double> table_size_y;
416 std::vector<double> table_yaw;
420 table_center_x.push_back(table.center_x);
421 table_center_y.push_back(table.center_y);
422 table_size_x.push_back(table.size_x);
423 table_size_y.push_back(table.size_y);
424 table_yaw.push_back(table.yaw);
427 moveit_msgs::CollisionObject co;
432 co.operation = moveit_msgs::CollisionObject::ADD;
433 co.primitives.resize(1);
434 co.primitives[0].type = shape_msgs::SolidPrimitive::BOX;
435 co.primitives[0].dimensions.resize(3);
436 co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_X] =
median(table_size_x);
437 co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_Y] =
median(table_size_y);
438 co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_Z] = 0.01;
439 co.primitive_poses.resize(1);
443 double roll_acc = 0.0, pitch_acc = 0.0;
444 for (
const geometry_msgs::Pose& pose: table_poses)
446 co.primitive_poses[0].position.x += pose.position.x;
447 co.primitive_poses[0].position.y += pose.position.y;
448 co.primitive_poses[0].position.z += pose.position.z;
454 co.primitive_poses[0].position.x = co.primitive_poses[0].position.x / (double)table_poses.size();
455 co.primitive_poses[0].position.y = co.primitive_poses[0].position.y / (double)table_poses.size();
456 co.primitive_poses[0].position.z = co.primitive_poses[0].position.z / (double)table_poses.size();
458 pitch_acc/(double)table_poses.size(),
461 co.primitive_poses[0].position.x +=
median(table_center_x);
462 co.primitive_poses[0].position.y +=
median(table_center_y);
463 co.primitive_poses[0].position.z -= co.primitives[0].dimensions[shape_msgs::SolidPrimitive::BOX_Z]/2.0;
465 ROS_INFO(
"[object detection] Adding a table at %s as a collision object, based on %u observations",
466 mtk::point2str3D(co.primitive_poses[0].position).c_str(), table_poses.size());
467 planning_scene_interface_.
addCollisionObjects(std::vector<moveit_msgs::CollisionObject>(1, co));
475 double min_area = std::numeric_limits<double>::max();
477 for (
size_t i0 = convex_hull.size() - 1, i1 = 0; i1 < convex_hull.size(); i0 = i1++)
479 convex_hull[i0].z = convex_hull[i1].z = 0;
487 double min0 = 0, max0 = 0;
488 double min1 = 0, max1 = 0;
489 for (
size_t j = 0; j < convex_hull.size(); ++j)
491 convex_hull[j].
z = 0;
494 double dot = U0.
dot(D);
505 double area = (max0 - min0) * (max1 - min1);
509 tf::Point center(origin + ((min0 + max0)/2.0) * U0 + ((min1 + max1)/2.0) * U1);
512 table.
size_x = max0 - min0;
513 table.
size_y = max1 - min1;
514 table.
yaw = std::atan2(U1.
y(), U1.
x());
525 double median(std::vector<double>& values)
527 std::vector<double>::iterator first = values.begin();
528 std::vector<double>::iterator last = values.end();
529 std::vector<double>::iterator middle = first + (last - first) / 2;
530 std::nth_element(first, middle, last);
534 bool transformPose(
const std::string& in_frame,
const std::string& out_frame,
535 const geometry_msgs::Pose& in_pose, geometry_msgs::Pose& out_pose)
537 geometry_msgs::PoseStamped in_stamped;
538 geometry_msgs::PoseStamped out_stamped;
540 in_stamped.header.frame_id = in_frame;
541 in_stamped.pose = in_pose;
545 tf_listener_.
transformPose(out_frame, in_stamped, out_stamped);
546 out_pose = out_stamped.pose;
561 ROS_ERROR(
"[object detection] Transformed pose has invalid orientation: %s", e.what());
566 ROS_ERROR(
"[object detection] Could not get sensor to arm transform: %s", e.what());
571 const object_recognition_msgs::ObjectInformation&
getObjInfo(
const object_recognition_msgs::ObjectType& obj_type)
573 if (objs_info_.find(obj_type.key) == objs_info_.end() )
576 object_recognition_msgs::GetObjectInformation srv;
577 srv.request.type = obj_type;
579 if (obj_info_srv_.
call(srv))
581 ROS_DEBUG(
"Database information retrieved for object '%s'", obj_type.key.c_str());
582 objs_info_[obj_type.key] = srv.response.information;
586 ROS_ERROR(
"Call to object information service with key '%s' failed", obj_type.key.c_str());
591 return objs_info_[obj_type.key];
596 std_msgs::ColorRGBA color;
597 color.r = float(rand())/RAND_MAX;
598 color.g = float(rand())/RAND_MAX;
599 color.b = float(rand())/RAND_MAX;
615 void addObject(object_recognition_msgs::RecognizedObject
object)
620 centroid = geometry_msgs::PoseStamped();
621 double confidence_acc = 0.0, roll_acc = 0.0, pitch_acc = 0.0, yaw_acc = 0.0;
622 for (
const object_recognition_msgs::RecognizedObject& obj:
objects)
625 centroid.header.frame_id = obj.pose.header.frame_id;
627 centroid.pose.position.x += obj.pose.pose.pose.position.x * obj.confidence;
628 centroid.pose.position.y += obj.pose.pose.pose.position.y * obj.confidence;
629 centroid.pose.position.z += obj.pose.pose.pose.position.z * obj.confidence;
630 roll_acc +=
mtk::roll(obj.pose.pose.pose) * obj.confidence;
631 pitch_acc +=
mtk::pitch (obj.pose.pose.pose) * obj.confidence;
632 yaw_acc +=
mtk::yaw(obj.pose.pose.pose) * obj.confidence;
634 confidence_acc += obj.confidence;
637 centroid.pose.position.x /= confidence_acc;
638 centroid.pose.position.y /= confidence_acc;
639 centroid.pose.position.z /= confidence_acc;
641 pitch_acc/confidence_acc,
642 yaw_acc/confidence_acc);
643 confidence = confidence_acc/(double)objects.size();
648 std::map<std::string, unsigned int> key_occurences;
649 for (
const object_recognition_msgs::RecognizedObject& obj:
objects)
650 key_occurences[obj.type.key]++;
652 std::string commonest_key;
653 std::map<std::string, unsigned int>::iterator it;
654 for(it = key_occurences.begin(); it != key_occurences.end(); it++)
656 if (it->second > key_occurences[commonest_key])
657 commonest_key = it->first;
659 return commonest_key;
662 object_recognition_msgs::ObjectType
getType()
const 664 std::string commonest_key =
getName();
665 for (
const object_recognition_msgs::RecognizedObject& obj:
objects)
666 if (obj.type.key == commonest_key)
669 return object_recognition_msgs::ObjectType();
675 std::vector<object_recognition_msgs::RecognizedObject>
objects;
682 int main(
int argc,
char** argv)
684 ros::init(argc, argv,
"object_detection_action_server");
const geometry_msgs::PoseStamped & getCentroid() const
ros::ServiceClient obj_info_srv_
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
turtlebot_arm_object_manipulation::ObjectDetectionFeedback feedback_
boost::shared_ptr< const Goal > acceptNewGoal()
actionlib::SimpleActionServer< turtlebot_arm_object_manipulation::ObjectDetectionAction > od_as_
tf::TransformListener tf_listener_
bool waitForServer(const ros::Duration &timeout=ros::Duration(0, 0)) const
static void pointMsgToTF(const geometry_msgs::Point &msg_v, Point &bt_v)
const object_recognition_msgs::ObjectInformation & getObjInfo(const object_recognition_msgs::ObjectType &obj_type)
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void tableCb(const object_recognition_msgs::TableArray &msg)
TableDescriptor getTableParams(std::vector< geometry_msgs::Point > convex_hull)
int main(int argc, char **argv)
turtlebot_arm_object_manipulation::ObjectDetectionResult result_
void addTable(const std::vector< geometry_msgs::Pose > &table_poses, const std::vector< TableDescriptor > &table_params)
double pitch(const tf::Transform &tf)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
boost::shared_ptr< interactive_markers::InteractiveMarkerServer > server
bool call(MReq &req, MRes &res)
const double CONFIDENCE_THRESHOLD
ros::Subscriber table_sub_
double yaw(const tf::Transform &tf)
const double CLUSTERING_THRESHOLD
void addCollisionObjects(const std::vector< moveit_msgs::CollisionObject > &collision_objects, const std::vector< moveit_msgs::ObjectColor > &object_colors=std::vector< moveit_msgs::ObjectColor >()) const
std::string getName() const
std::string pose2str3D(const geometry_msgs::Pose &pose)
turtlebot_arm_object_manipulation::ObjectDetectionGoalConstPtr goal_
double roll(const tf::Transform &tf)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
ROSCPP_DECL void spin(Spinner &spinner)
int addObjects(const std::vector< DetectionBin > &detection_bins)
std::vector< geometry_msgs::Pose > table_poses_
ObjectDetectionServer(const std::string name)
std::string point2str3D(const geometry_msgs::Point &point)
std::string toString() const
TFSIMD_FORCE_INLINE const tfScalar & x() const
TFSIMD_FORCE_INLINE tfScalar dot(const Vector3 &v) const
void setPreempted(const Result &result=Result(), const std::string &text=std::string(""))
ros::Duration ork_preempt_timeout_
TFSIMD_FORCE_INLINE const tfScalar & z() const
ros::Publisher clear_table_pub_
bool waitForExistence(ros::Duration timeout=ros::Duration(-1))
SimpleClientGoalState sendGoalAndWait(const Goal &goal, const ros::Duration &execute_timeout=ros::Duration(0, 0), const ros::Duration &preempt_timeout=ros::Duration(0, 0))
void registerPreemptCallback(boost::function< void()> cb)
TFSIMD_FORCE_INLINE const tfScalar & y() const
geometry_msgs::PoseStamped centroid
std_msgs::ColorRGBA getRandColor(float alpha=1.0)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::Publisher clear_objs_pub_
unsigned int countObjects() const
TFSIMD_FORCE_INLINE Vector3 & normalize()
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
const unsigned CALLS_TO_ORK_TABLETOP
bool transformPose(const std::string &in_frame, const std::string &out_frame, const geometry_msgs::Pose &in_pose, geometry_msgs::Pose &out_pose)
std::vector< TableDescriptor > table_params_
std::vector< std::string > getKnownObjectNames(bool with_type=false)
void removeCollisionObjects(const std::vector< std::string > &object_ids) const
static geometry_msgs::Quaternion createQuaternionMsgFromRollPitchYaw(double roll, double pitch, double yaw)
double median(std::vector< double > &values)
ResultConstPtr getResult() const
object_recognition_msgs::ObjectType getType() const
void addObject(object_recognition_msgs::RecognizedObject object)
void registerGoalCallback(boost::function< void()> cb)
std::vector< object_recognition_msgs::RecognizedObject > objects
ROSCPP_DECL void spinOnce()
std::map< std::string, object_recognition_msgs::ObjectInformation > objs_info_
moveit::planning_interface::PlanningSceneInterface planning_scene_interface_
ros::Duration ork_execute_timeout_
actionlib::SimpleActionClient< object_recognition_msgs::ObjectRecognitionAction > ork_ac_
double distance3D(double ax, double ay, double az, double bx, double by, double bz)