00001 #include "cleaning_plan_alg_node.h"
00002
00003 using namespace std;
00004 using namespace cv;
00005
00006 CleaningPlanAlgNode::CleaningPlanAlgNode(void) :
00007 algorithm_base::IriBaseAlgorithm<CleaningPlanAlgorithm>()
00008 {
00009
00010
00011
00012
00013 this->image_plan_out_publisher_ = this->public_node_handle_.advertise<sensor_msgs::Image>("image_plan_out", 1);
00014 this->visualization_markers_publisher_ = this->public_node_handle_.advertise<visualization_msgs::MarkerArray>("visualization_markers", 1);
00015
00016
00017
00018
00019 this->representation_to_string_server_ = this->public_node_handle_.advertiseService("representation_to_string", &CleaningPlanAlgNode::representation_to_stringCallback, this);
00020 this->get_dirty_areas_state_representation_server_ = this->public_node_handle_.advertiseService("get_dirty_areas_state_representation", &CleaningPlanAlgNode::get_dirty_areas_state_representationCallback, this);
00021 this->get_trajectories_from_plan_server_ = this->public_node_handle_.advertiseService("get_trajectories_from_plan", &CleaningPlanAlgNode::get_trajectories_from_planCallback, this);
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 }
00032
00033 CleaningPlanAlgNode::~CleaningPlanAlgNode(void)
00034 {
00035
00036 }
00037
00038 void CleaningPlanAlgNode::mainNodeThread(void)
00039 {
00040
00041
00042
00043
00044
00045
00046
00047
00048 }
00049
00050
00051
00052
00053 bool CleaningPlanAlgNode::representation_to_stringCallback(estirabot_msgs::RepresentationToString::Request &req, estirabot_msgs::RepresentationToString::Response &res)
00054 {
00055 ROS_DEBUG("CleaningPlanAlgNode::representation_to_stringCallback: New Request Received!");
00056
00057
00058
00059
00060
00061
00062 res.state_string = this->ellipses_representation.getStateString(req.dirty_areas);
00063
00064
00065
00066
00067
00068 return true;
00069 }
00070
00071 bool CleaningPlanAlgNode::get_dirty_areas_state_representationCallback(iri_clean_board::StateRepresentation::Request &req, iri_clean_board::StateRepresentation::Response &res)
00072 {
00073 ROS_INFO("CleaningPlanAlgNode::get_dirty_areas_state_representationCallback: New Request Received!");
00074
00075 cv_bridge::CvImagePtr cv_ptr;
00076
00077 try
00078 {
00079 cv_ptr = cv_bridge::toCvCopy(req.image, sensor_msgs::image_encodings::TYPE_8UC1);
00080 }
00081 catch (cv_bridge::Exception& e)
00082 {
00083 ROS_ERROR("cv_bridge exception: %s", e.what());
00084 return false;
00085 }
00086
00087
00088 this->alg_.lock();
00089 this->get_dirty_areas_state_representation_mutex_.enter();
00090
00091 this->ellipses_representation.createNewState(cv_ptr->image);
00092
00093 for( size_t i = 0; i < ellipses_representation.getEllipsesNumber(); i++ ) {
00094 ROS_DEBUG_STREAM("ELIPSES: DATA");
00095 ROS_DEBUG_STREAM("Center: " << ellipses_representation.getCurrentEllipses()[i].center <<
00096 " Size: " << ellipses_representation.getCurrentEllipses()[i].size.width << "," << ellipses_representation.getCurrentEllipses()[i].size.height);
00097 ROS_DEBUG_STREAM("Angle: " << (ellipses_representation.getCurrentEllipses()[i].angle/180)*M_PI);
00098 }
00099
00100 if (ellipses_representation.getEllipsesNumber() > 0) {
00101 res.dirty_areas = this->ellipses_representation.getRosDirtyAreas();
00102 res.distances = this->ellipses_representation.distancesBetweenEllipses(res.dirty_areas);
00103 res.traversed_ellipses = this->ellipses_representation.getTraversedEllipses(res.dirty_areas);
00104 res.state_string = this->ellipses_representation.getStateString(res.dirty_areas);
00105 res.arm_position = this->ellipses_representation.getNearestEllipse();
00106 res.is_clean = false;
00107 }
00108 else {
00109 res.state_string = "";
00110 res.is_clean = true;
00111 }
00112
00113 this->ellipses_representation.writeStateToFile(this->file_planner_state, res.dirty_areas);
00114
00115
00116 this->alg_.unlock();
00117 this->get_dirty_areas_state_representation_mutex_.exit();
00118
00119 return true;
00120 }
00121
00122
00123 bool CleaningPlanAlgNode::get_trajectories_from_planCallback(iri_clean_board::PlanToTrajectories::Request &req, iri_clean_board::PlanToTrajectories::Response &res)
00124 {
00125 ROS_DEBUG("CleaningPlanAlgNode::get_trajectories_from_planCallback: New Request Received!");
00126
00127
00128
00129
00130
00131 savePlanningResponse(req, res);
00132
00133 if ( (res.poses.size()>0) && (this->image_plan_out_publisher_.getNumSubscribers()>0) ){
00134 cv_bridge::CvImage cvbridge_aux;
00135 cv::Mat image_bgr;
00136 cvbridge_aux.encoding = sensor_msgs::image_encodings::BGR8;
00137 cvbridge_aux.image = this->ellipses_representation.show_image;
00138 cvbridge_aux.header.stamp = ros::Time::now();
00139
00140 this->Image_msg_ = *cvbridge_aux.toImageMsg();
00141 this->image_plan_out_publisher_.publish(this->Image_msg_);
00142 }
00143
00144
00145
00146
00147
00148 return true;
00149 }
00150
00151
00152 void CleaningPlanAlgNode::savePlanningResponse(iri_clean_board::PlanToTrajectories::Request req,
00153 iri_clean_board::PlanToTrajectories::Response &res)
00154 {
00155 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
00156 bool is_real_movement;
00157
00158 size_t i = 0;
00159 uint j = 0;
00160
00161 if (this->no_planning) {
00162 getNearestCleanPlan(req, res);
00163 return;
00164 }
00165 else if (this->no_perception) {
00166 getNoPerceptionCleanPlan(req, res);
00167 return;
00168 }
00169
00170 pcl::fromROSMsg (req.pointcloud_in, *cloud);
00171
00172 show_dirty_areas_information(req.pointcloud_in, req.dirty_areas);
00173
00174 ROS_INFO_STREAM("Got number of actions: " << req.actions.size());
00175
00176 while ( (i < req.actions.size()) &&
00177 (j < this->max_number_actions) && (j < req.dirty_areas.size() ) )
00178 {
00179
00180 std::stringstream ss;
00181 for (size_t k = 0; k< req.target_ellipses[i].indexes.size(); ++k) { ss << req.target_ellipses[i].indexes[k] << ","; }
00182 ROS_INFO_STREAM("Adding movement " << req.actions[i] << "(" << ss.str() << ")");
00183
00184 is_real_movement= this->alg_.getMovementFromAction(req.dirty_areas, req.actions[i],
00185 req.target_ellipses[i],
00186 this->ellipses_representation,
00187 cloud, req.plane_coefficients,
00188 res.poses, res.poses_2d_coordinates, res.secondary_arm );
00189 if (is_real_movement)
00190 j++;
00191 i++;
00192 }
00193
00194 if (j == 0) {
00195 res.movement = false;
00196 }
00197 else {
00198 res.movement = true;
00199 }
00200 }
00201
00202
00203 void CleaningPlanAlgNode::show_dirty_areas_information(sensor_msgs::PointCloud2 pointcloud, std::vector< estirabot_msgs::DirtyArea > dirty_areas)
00204 {
00205 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_cloud (new pcl::PointCloud<pcl::PointXYZ>);
00206 visualization_msgs::MarkerArray markers_msg;
00207
00208 if(this->visualization_markers_publisher_.getNumSubscribers())
00209 {
00210 pcl::fromROSMsg (pointcloud, *pcl_cloud);
00211
00212 for (size_t i = 0; i < dirty_areas.size(); i++) {
00213
00214 visualization_msgs::Marker marker;
00215 marker.header.frame_id = pointcloud.header.frame_id;
00216 marker.ns = "Dirty areas";
00217 marker.id = i;
00218 marker.header.stamp = ros::Time();
00219 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00220 marker.action = visualization_msgs::Marker::ADD;
00221
00222 pcl::PointXYZ point = pcl_cloud->at(dirty_areas[i].ellipse.center.x,dirty_areas[i].ellipse.center.y);
00223 marker.pose.position.x = point.x;
00224 marker.pose.position.y = point.y;
00225 marker.pose.position.z = point.z - 0.05;
00226 marker.pose.orientation.x = 0.0;
00227 marker.pose.orientation.y = 0.0;
00228 marker.pose.orientation.z = 0.0;
00229 marker.pose.orientation.w = 1.0;
00230
00231
00232 marker.scale.x = 0.1;
00233 marker.scale.y = 0.1;
00234 marker.scale.z = 0.1;
00235
00236 marker.color.a = 1.0;
00237 marker.color.r = 1.0;
00238 marker.color.g = 0.0;
00239 marker.color.b = 0.0;
00240
00241 std::stringstream ss;
00242 ss << 60 + dirty_areas[i].id;
00243 marker.text=ss.str();
00244
00245
00246 markers_msg.markers.push_back(marker);
00247 }
00248
00249
00250 for (size_t i = markers_msg.markers.size(); i < 10; i++) {
00251
00252 visualization_msgs::Marker marker;
00253 marker.header.frame_id = pointcloud.header.frame_id;
00254 marker.ns = "Dirty areas";
00255 marker.id = i;
00256 marker.header.stamp = ros::Time();
00257 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00258 marker.action = visualization_msgs::Marker::ADD;
00259
00260 marker.pose.position.x = 0.0;
00261 marker.pose.position.y = 0.0;
00262 marker.pose.position.z = (0.1 * i);
00263 marker.pose.orientation.x = 0.0;
00264 marker.pose.orientation.y = 0.0;
00265 marker.pose.orientation.z = 0.0;
00266 marker.pose.orientation.w = 1.0;
00267
00268
00269 marker.scale.x = 0.1;
00270 marker.scale.y = 0.1;
00271 marker.scale.z = 0.1;
00272
00273 marker.color.a = 0.0;
00274 marker.color.r = 1.0;
00275 marker.color.g = 0.0;
00276 marker.color.b = 0.0;
00277
00278 marker.text="as";
00279
00280 markers_msg.markers.push_back(marker);
00281 }
00282
00283 this->MarkerArray_msg_ = markers_msg;
00284
00285
00286 this->visualization_markers_publisher_.publish(this->MarkerArray_msg_);
00287 }
00288 }
00289
00290
00291 void CleaningPlanAlgNode::getNearestCleanPlan(iri_clean_board::PlanToTrajectories::Request req,
00292 iri_clean_board::PlanToTrajectories::Response &res)
00293 {
00294 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
00295
00296 pcl::fromROSMsg (req.pointcloud_in, *cloud);
00297
00298
00299 std::vector< size_t > plan = ellipses_representation.getGoodPathThroughAllDirtyAreas(req.dirty_areas);
00300 std::vector< size_t >::iterator plan_it;
00301
00302 for ( plan_it = plan.begin() ; plan_it < plan.end(); plan_it++ ) {
00303 estirabot_msgs::ArrayIndexes target_ellipses;
00304 std::string movement_type;
00305 target_ellipses.indexes.push_back(*plan_it);
00306
00307 if (this->board_plan) {
00308 cv::RotatedRect ellipse = this->ellipses_representation.getCurrentEllipses()[*plan_it];
00309
00310 movement_type = "smallClean";
00311 if (1) {
00312 if (ellipse.size.width > 50)
00313 movement_type = "circularClean";
00314 else if (ellipse.size.height > 50)
00315 movement_type = "straightClean";
00316 }
00317 }
00318 else
00319 movement_type = "pickUp";
00320
00321 alg_.getMovementFromAction(req.dirty_areas, "pickUp", target_ellipses,
00322 this->ellipses_representation,
00323 cloud, req.plane_coefficients,
00324 res.poses, res.poses_2d_coordinates, res.secondary_arm );
00325 }
00326
00327 res.movement = true;
00328 }
00329
00330 void CleaningPlanAlgNode::getNoPerceptionCleanPlan(iri_clean_board::PlanToTrajectories::Request req, iri_clean_board::PlanToTrajectories::Response &res)
00331 {
00332 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
00333 pcl::fromROSMsg (req.pointcloud_in, *cloud);
00334
00335 ROS_INFO_STREAM("Creating trajectories without ellipses perception.");
00336 req.actions.clear();
00337 req.actions.push_back("NoPerception");
00338 this->alg_.getMovementFromAction(req.dirty_areas, req.actions[0],
00339 req.target_ellipses[0],
00340 this->ellipses_representation,
00341 cloud, req.plane_coefficients,
00342 res.poses, res.poses_2d_coordinates, res.secondary_arm );
00343
00344 res.movement = true;
00345 }
00346
00347
00348
00349
00350
00351
00352 void CleaningPlanAlgNode::node_config_update(Config &config, uint32_t level)
00353 {
00354 this->alg_.lock();
00355
00356 this->max_number_actions = config.max_number_actions;
00357 this->no_planning = config.no_planning;
00358 this->no_perception = config.no_perceptions;
00359 this->board_plan = config.board_plan;
00360 this->file_planner_state = config.file_planner_state;
00361
00362
00363 this->ellipses_representation.config_update(config, level);
00364
00365 this->alg_.unlock();
00366 }
00367
00368 void CleaningPlanAlgNode::addNodeDiagnostics(void)
00369 {
00370 }
00371
00372
00373 int main(int argc,char *argv[])
00374 {
00375 return algorithm_base::main<CleaningPlanAlgNode>(argc, argv, "cleaning_plan_alg_node");
00376 }
00377