turtlebot_exploration_3d.cpp
Go to the documentation of this file.
00001 // Related headers:
00002 #include "exploration.h"
00003 #include "navigation_utils.h"
00004 #include "gpregressor.h"
00005 #include "covMaterniso3.h"
00006 
00007 //C library headers:
00008 #include <iostream>
00009 #include <fstream>
00010 // #include <chrono>
00011 // #include <iterator>
00012 // #include <ctime>
00013 
00014 //C++ library headers:  NONE
00015 #include <visualization_msgs/Marker.h>
00016 #include <visualization_msgs/MarkerArray.h>
00017 
00018 //other library headers:  NONE
00019 
00020 
00021 using namespace std;
00022 
00023 
00024 int main(int argc, char **argv) {
00025     ros::init(argc, argv, "turtlebot_exploration_3d");
00026     ros::NodeHandle nh;
00027 
00028     // Initialize time
00029     time_t rawtime;
00030     struct tm * timeinfo;
00031     char buffer[80];
00032     time (&rawtime);
00033     timeinfo = localtime(&rawtime);
00034     // strftime(buffer,80,"Trajectory_%R_%S_%m%d_DA.txt",timeinfo);
00035     // std::string logfilename(buffer);
00036     // std::cout << logfilename << endl;
00037 
00038     strftime(buffer,80,"Octomap3D_%m%d_%R_%S.ot",timeinfo);
00039     octomap_name_3d = buffer;
00040 
00041 
00042     ros::Subscriber kinect_sub = nh.subscribe<sensor_msgs::PointCloud2>("/camera/depth_registered/points", 1, kinectCallbacks);// need to change##########
00043     ros::Publisher GoalMarker_pub = nh.advertise<visualization_msgs::Marker>( "Goal_Marker", 1 );
00044     ros::Publisher Candidates_pub = nh.advertise<visualization_msgs::MarkerArray>("Candidate_MIs", 1);
00045     ros::Publisher Frontier_points_pub = nh.advertise<visualization_msgs::Marker>("Frontier_points", 1);
00046     ros::Publisher pub_twist = nh.advertise<geometry_msgs::Twist>("/cmd_vel_mux/input/teleop", 1);
00047     ros::Publisher Octomap_pub = nh.advertise<octomap_msgs::Octomap>("octomap_3d",1);
00048 
00049 
00050     tf_listener = new tf::TransformListener();
00051     tf::StampedTransform transform;
00052     tf::Quaternion Goal_heading; // robot's heading direction
00053 
00054     visualization_msgs::MarkerArray CandidatesMarker_array;
00055     visualization_msgs::Marker Frontier_points_cubelist;
00056     geometry_msgs::Twist twist_cmd;
00057 
00058     ros::Time now_marker = ros::Time::now();
00059    
00060     // Initialize parameters 
00061     int max_idx = 0;
00062 
00063     point3d Sensor_PrincipalAxis(1, 0, 0);
00064     octomap::OcTreeNode *n;
00065     octomap::OcTree new_tree(octo_reso);
00066     octomap::OcTree new_tree_2d(octo_reso);
00067     cur_tree = &new_tree;
00068     cur_tree_2d = &new_tree_2d;
00069     point3d next_vp;
00070 
00071     bool got_tf = false;
00072     bool arrived;
00073     
00074     // Update the initial location of the robot
00075     for(int i =0; i < 6; i++){
00076         // Update the pose of the robot
00077         got_tf = false;
00078         while(!got_tf){
00079         try{
00080             tf_listener->lookupTransform("/map", "/camera_rgb_frame", ros::Time(0), transform);// need to change tf of kinect###############
00081             kinect_orig = point3d(transform.getOrigin().x(), transform.getOrigin().y(), transform.getOrigin().z());
00082             got_tf = true;
00083         }
00084         catch (tf::TransformException ex) {
00085             ROS_WARN("Wait for tf: Kinect frame"); 
00086         } 
00087         ros::Duration(0.05).sleep();
00088         }
00089 
00090         // Take a Scan
00091         ros::spinOnce();
00092 
00093         // Rotate another 60 degrees
00094         twist_cmd.linear.x = twist_cmd.linear.y = twist_cmd.angular.z = 0;
00095         ros::Time start_turn = ros::Time::now();
00096 
00097         ROS_WARN("Rotate 60 degrees");
00098         while (ros::Time::now() - start_turn < ros::Duration(2.6)){ // turning duration - second
00099         twist_cmd.angular.z = 0.6; // turning speed
00100         // turning angle = turning speed * turning duration / 3.14 * 180
00101         pub_twist.publish(twist_cmd);
00102         ros::Duration(0.05).sleep();
00103         }
00104         // stop
00105         twist_cmd.angular.z = 0;
00106         pub_twist.publish(twist_cmd);
00107 
00108     }
00109 
00110     // steps robot taken, counter
00111     int robot_step_counter = 0;
00112 
00113     while (ros::ok())
00114     {
00115         vector<vector<point3d>> frontier_groups=extractFrontierPoints(cur_tree);
00116         
00117         //frontier_groups.clear();//in the next line
00118         unsigned long int o = 0;
00119         for(vector<vector<point3d>>::size_type e = 0; e < frontier_groups.size(); e++) {
00120             o = o+frontier_groups[e].size();
00121         }
00122 
00123         Frontier_points_cubelist.points.resize(o);
00124         ROS_INFO("frontier points %ld", o);
00125         now_marker = ros::Time::now();
00126         Frontier_points_cubelist.header.frame_id = "map";
00127         Frontier_points_cubelist.header.stamp = now_marker;
00128         Frontier_points_cubelist.ns = "frontier_points_array";
00129         Frontier_points_cubelist.id = 0;
00130         Frontier_points_cubelist.type = visualization_msgs::Marker::CUBE_LIST;
00131         Frontier_points_cubelist.action = visualization_msgs::Marker::ADD;
00132         Frontier_points_cubelist.scale.x = octo_reso;
00133         Frontier_points_cubelist.scale.y = octo_reso;
00134         Frontier_points_cubelist.scale.z = octo_reso;
00135         Frontier_points_cubelist.color.a = 1.0;
00136         Frontier_points_cubelist.color.r = (double)255/255;
00137         Frontier_points_cubelist.color.g = 0;
00138         Frontier_points_cubelist.color.b = (double)0/255;
00139         Frontier_points_cubelist.lifetime = ros::Duration();
00140 
00141         unsigned long int t = 0;
00142         int l = 0;
00143         geometry_msgs::Point q;
00144         for(vector<vector<point3d>>::size_type n = 0; n < frontier_groups.size(); n++) { 
00145             for(vector<point3d>::size_type m = 0; m < frontier_groups[n].size(); m++){
00146                q.x = frontier_groups[n][m].x();
00147                q.y = frontier_groups[n][m].y();
00148                q.z = frontier_groups[n][m].z()+octo_reso;
00149                Frontier_points_cubelist.points.push_back(q); 
00150                
00151             }
00152             t++;
00153         }
00154         ROS_INFO("Publishing %ld frontier_groups", t);
00155         
00156         Frontier_points_pub.publish(Frontier_points_cubelist); //publish frontier_points
00157         Frontier_points_cubelist.points.clear();           
00158 
00159         // Generate Candidates
00160         vector<pair<point3d, point3d>> candidates = extractCandidateViewPoints(frontier_groups, kinect_orig, num_of_samples); 
00161         std::random_shuffle(candidates.begin(),candidates.end()); // shuffle to select a subset
00162         vector<pair<point3d, point3d>> gp_test_poses = candidates;
00163         ROS_INFO("Candidate View Points: %luGenereated, %d evaluating...", candidates.size(), num_of_samples_eva);
00164         int temp_size = candidates.size()-3;
00165         if (temp_size < 1) {
00166             ROS_ERROR("Very few candidates generated, maybe finishing with exploration...");
00167             nh.shutdown();
00168             return 0;
00169         }
00170 
00171         // Generate Testing poses
00172         candidates.resize(min(num_of_samples_eva,temp_size));
00173         frontier_groups.clear();
00174 
00175 // Evaluate MI for every candidate view points
00176         vector<double>  MIs(candidates.size());
00177         double before = countFreeVolume(cur_tree);
00178         // int max_idx = 0;
00179         double begin_mi_eva_secs, end_mi_eva_secs;
00180         begin_mi_eva_secs = ros::Time::now().toSec();
00181 
00182         #pragma omp parallel for
00183         for(int i = 0; i < candidates.size(); i++) 
00184         {
00185             auto c = candidates[i];
00186             // Evaluate Mutual Information
00187             Sensor_PrincipalAxis = point3d(1.0, 0.0, 0.0);
00188             Sensor_PrincipalAxis.rotate_IP(c.second.roll(), c.second.pitch(), c.second.yaw() );
00189             octomap::Pointcloud hits = castSensorRays(cur_tree, c.first, Sensor_PrincipalAxis);
00190             
00191             // Considering pure MI for decision making
00192             MIs[i] = calc_MI(cur_tree, c.first, hits, before);
00193             
00194             // Normalize the MI with distance
00195             // MIs[i] = calc_MI(cur_tree, c.first, hits, before) / 
00196             //     sqrt(pow(c.first.x()-kinect_orig.x(),2) + pow(c.first.y()-kinect_orig.y(),2));
00197 
00198             // Pick the Candidate view point with max MI
00199             // if (MIs[i] > MIs[max_idx])
00200             // {
00201             //     max_idx = i;
00202             // }
00203         }
00204 
00205 
00206         // Bayesian Optimization for actively selecting candidate
00207         double train_time, test_time;
00208         GPRegressor g(100, 3, 0.01);
00209         for (int bay_itr = 0; bay_itr < num_of_bay; bay_itr++) {
00210             //Initialize gp regression
00211             
00212             MatrixXf gp_train_x(candidates.size(), 2), gp_train_label(candidates.size(), 1), gp_test_x(gp_test_poses.size(), 2);
00213 
00214             for (int i=0; i< candidates.size(); i++){
00215                 gp_train_x(i,0) = candidates[i].first.x();
00216                 gp_train_x(i,1) = candidates[i].first.y();
00217                 gp_train_label(i) = MIs[i];
00218             }
00219 
00220             for (int i=0; i< gp_test_poses.size(); i++){
00221                 gp_test_x(i,0) = gp_test_poses[i].first.x();
00222                 gp_test_x(i,1) = gp_test_poses[i].first.y();
00223             }
00224 
00225             // Perform GP regression
00226             MatrixXf gp_mean_MI, gp_var_MI;
00227             train_time = ros::Time::now().toSec();
00228             g.train(gp_train_x, gp_train_label);
00229             train_time = ros::Time::now().toSec() - train_time;
00230 
00231             test_time = ros::Time::now().toSec();
00232             g.test(gp_test_x, gp_mean_MI, gp_var_MI);
00233             test_time = ros::Time::now().toSec() - test_time;
00234             ROS_INFO("GP: Train(%zd) took %f secs , Test(%zd) took %f secs", candidates.size(), train_time, gp_test_poses.size(), test_time);        
00235 
00236             // Get Acquisition function
00237             double beta = 2.4;
00238             vector<double>  bay_acq_fun(gp_test_poses.size());
00239             for (int i = 0; i < gp_test_poses.size(); i++) {
00240                 bay_acq_fun[i] = gp_mean_MI(i) + beta*gp_var_MI(i);
00241             }
00242             vector<int> idx_acq = sort_MIs(bay_acq_fun);
00243 
00244             // evaluate MI, add to the candidate
00245             auto c = gp_test_poses[idx_acq[0]];
00246             Sensor_PrincipalAxis = point3d(1.0, 0.0, 0.0);
00247             Sensor_PrincipalAxis.rotate_IP(c.second.roll(), c.second.pitch(), c.second.yaw() );
00248             octomap::Pointcloud hits = castSensorRays(cur_tree, c.first, Sensor_PrincipalAxis);
00249             candidates.push_back(c);
00250             MIs.push_back(calc_MI(cur_tree, c.first, hits, before));
00251         }
00252         
00253         end_mi_eva_secs = ros::Time::now().toSec();
00254         ROS_INFO("Mutual Infomation Eva took:  %3.3f Secs.", end_mi_eva_secs - begin_mi_eva_secs);
00255 
00256         // Normalize the MI with distance
00257         for(int i = 0; i < candidates.size(); i++) {
00258             auto c = candidates[i];
00259             MIs[i] = MIs[i] / 
00260                 sqrt(pow(c.first.x()-kinect_orig.x(),2) + pow(c.first.y()-kinect_orig.y(),2));
00261         }
00262 
00263         // sort vector MIs, with idx_MI, descending
00264         vector<int> idx_MI = sort_MIs(MIs);
00265 
00266         // Publish the candidates as marker array in rviz
00267         tf::Quaternion MI_heading;
00268         MI_heading.setRPY(0.0, -PI/2, 0.0);
00269         MI_heading.normalize();
00270         
00271         CandidatesMarker_array.markers.resize(candidates.size());
00272         for (int i = 0; i < candidates.size(); i++)
00273         {
00274             CandidatesMarker_array.markers[i].header.frame_id = "map";
00275             CandidatesMarker_array.markers[i].header.stamp = ros::Time::now();
00276             CandidatesMarker_array.markers[i].ns = "candidates";
00277             CandidatesMarker_array.markers[i].id = i;
00278             CandidatesMarker_array.markers[i].type = visualization_msgs::Marker::ARROW;
00279             CandidatesMarker_array.markers[i].action = visualization_msgs::Marker::ADD;
00280             CandidatesMarker_array.markers[i].pose.position.x = candidates[i].first.x();
00281             CandidatesMarker_array.markers[i].pose.position.y = candidates[i].first.y();
00282             CandidatesMarker_array.markers[i].pose.position.z = candidates[i].first.z();
00283             CandidatesMarker_array.markers[i].pose.orientation.x = MI_heading.x();
00284             CandidatesMarker_array.markers[i].pose.orientation.y = MI_heading.y();
00285             CandidatesMarker_array.markers[i].pose.orientation.z = MI_heading.z();
00286             CandidatesMarker_array.markers[i].pose.orientation.w = MI_heading.w();
00287             CandidatesMarker_array.markers[i].scale.x = (double)2.0*MIs[i]/MIs[idx_MI[0]];
00288             CandidatesMarker_array.markers[i].scale.y = 0.2;
00289             CandidatesMarker_array.markers[i].scale.z = 0.2;
00290             CandidatesMarker_array.markers[i].color.a = (double)MIs[i]/MIs[idx_MI[0]];
00291             CandidatesMarker_array.markers[i].color.r = 0.0;
00292             CandidatesMarker_array.markers[i].color.g = 1.0;
00293             CandidatesMarker_array.markers[i].color.b = 0.0;
00294         }
00295         Candidates_pub.publish(CandidatesMarker_array);
00296         CandidatesMarker_array.markers.clear();
00297         candidates.clear();
00298 
00299         // loop in the idx_MI, if the candidate with max MI cannot be achieved, 
00300         // switch to a sub-optimal MI.
00301         arrived = false;
00302         int idx_ptr = 0;
00303 
00304         while (!arrived) {
00305             // Setup the Goal
00306             next_vp = point3d(candidates[idx_MI[idx_ptr]].first.x(),candidates[idx_MI[idx_ptr]].first.y(),candidates[idx_MI[idx_ptr]].first.z());
00307             Goal_heading.setRPY(0.0, 0.0, candidates[idx_MI[idx_ptr]].second.yaw());
00308             Goal_heading.normalize();
00309             ROS_INFO("Max MI : %f , @ location: %3.2f  %3.2f  %3.2f", MIs[idx_MI[idx_ptr]], next_vp.x(), next_vp.y(), next_vp.z() );
00310             
00311             // Publish the goal as a Marker in rviz
00312             visualization_msgs::Marker marker;
00313             marker.header.frame_id = "map";
00314             marker.header.stamp = ros::Time();
00315             marker.ns = "goal_marker";
00316             marker.id = 0;
00317             marker.type = visualization_msgs::Marker::ARROW;
00318             marker.action = visualization_msgs::Marker::ADD;
00319             marker.pose.position.x = next_vp.x();
00320             marker.pose.position.y = next_vp.y();
00321             marker.pose.position.z = 1.0;
00322             marker.pose.orientation.x = Goal_heading.x();
00323             marker.pose.orientation.y = Goal_heading.y();
00324             marker.pose.orientation.z = Goal_heading.z();
00325             marker.pose.orientation.w = Goal_heading.w();
00326             marker.scale.x = 0.5;
00327             marker.scale.y = 0.1;
00328             marker.scale.z = 0.1;
00329             marker.color.a = 1.0; // Don't forget to set the alpha!
00330             marker.color.r = 1.0;
00331             marker.color.g = 1.0;
00332             marker.color.b = 0.0;
00333             GoalMarker_pub.publish( marker );
00334 
00335             // Send the Robot 
00336             arrived = goToDest(next_vp, Goal_heading);
00337 
00338             if(arrived)
00339             {
00340                 // Update the initial location of the robot
00341                 got_tf = false;
00342                 while(!got_tf){
00343                 try{
00344                     tf_listener->lookupTransform("/map", "/camera_rgb_frame", ros::Time(0), transform);// need to change tf of kinect###############
00345                     kinect_orig = point3d(transform.getOrigin().x(), transform.getOrigin().y(), transform.getOrigin().z());
00346                     got_tf = true;
00347                 }
00348                 catch (tf::TransformException ex) {
00349                     ROS_WARN("Wait for tf: Kinect frame"); 
00350                 } 
00351                 ros::Duration(0.05).sleep();
00352                 }
00353                 // Update Octomap
00354                 ros::spinOnce();
00355                 ROS_INFO("Succeed, new Map Free Volume: %f", countFreeVolume(cur_tree));
00356                 robot_step_counter++;
00357 
00358                 // prepare octomap msg
00359                 octomap_msgs::binaryMapToMsg(*cur_tree, msg_octomap);
00360                 msg_octomap.binary = 1;
00361                 msg_octomap.id = 1;
00362                 msg_octomap.resolution = octo_reso;
00363                 msg_octomap.header.frame_id = "/map";
00364                 msg_octomap.header.stamp = ros::Time::now();
00365                 Octomap_pub.publish(msg_octomap);
00366                 ROS_INFO("Octomap updated in RVIZ");
00367 
00368                 // // Send out results to file.
00369                 // explo_log_file.open(logfilename, std::ofstream::out | std::ofstream::app);
00370                 // explo_log_file << "DA Step ," << robot_step_counter << ", Current Entropy ," << countFreeVolume(cur_tree) << ", time, " << ros::Time::now().toSec() << endl;
00371                 // explo_log_file.close();
00372 
00373             }
00374             else
00375             {
00376                 ROS_WARN("Failed to drive to the %d th goal, switch to the sub-optimal..", idx_ptr);
00377                 idx_ptr++;
00378                 if(idx_ptr > MIs.size()) {
00379                     ROS_ERROR("None of the goal is valid for path planning, shuting down the node");
00380                     nh.shutdown();
00381                 }
00382             }
00383 
00384         }
00385 
00386         
00387         // r.sleep();
00388     }
00389     nh.shutdown();          
00390     return 0;
00391 }


turtlebot_exploration_3d
Author(s): Bona , Shawn
autogenerated on Thu Jun 6 2019 21:00:32