ScavTaskHumanFollowing.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <math.h>
00003 
00004 #include "geometry_msgs/PoseStamped.h"
00005 #include <geometry_msgs/Twist.h>
00006 #include "std_msgs/String.h"
00007 
00008 #include <pcl_ros/point_cloud.h>
00009 #include <pcl/point_types.h>
00010 #include <opencv2/highgui/highgui.hpp>
00011 #include <cv_bridge/cv_bridge.h>
00012 #include <image_transport/image_transport.h>
00013 #include <sensor_msgs/image_encodings.h>
00014 
00015 #include "ScavTaskHumanFollowing.h"
00016 
00017 namespace scav_task_human_following {
00018 
00019 sensor_msgs::ImageConstPtr wb_image;
00020 sensor_msgs::ImageConstPtr wb_image_candidate;
00021 std::string wb_path_to_image;
00022 
00023 
00024 ScavTaskHumanFollowing::ScavTaskHumanFollowing(ros::NodeHandle *nh, std::string dir) : ac("move_base", true)
00025 {
00026     this->nh = nh;
00027     directory = dir;
00028     task_description = "following a human for a distance";
00029     task_name = "Human following";
00030     certificate = ""; 
00031 
00032     while (!ac.waitForServer(ros::Duration(5.0)))
00033     {
00034         ROS_INFO("Waiting for the move_base action server to come up");
00035     }
00036 
00037     cmd_vel_pub = nh->advertise<geometry_msgs::Twist>("cmd_vel", 1);
00038 
00039     sound_pub = nh->advertise<sound_play::SoundRequest>("robotsound", 1); 
00040 
00041     search_planner_simple = new SearchPlannerSimple(nh); 
00042 
00043     task_completed = false;
00044     human_detected = -1;
00045 }
00046 
00047 
00048 void ScavTaskHumanFollowing::callback_human_detected(const geometry_msgs::PoseStamped::ConstPtr& msg)
00049 {
00050     if (human_detected == -1)
00051         search_planner_simple->cancelCurrentGoal();
00052 
00053     detected_time = ros::Time::now();
00054 
00055     ROS_INFO("Person detected");
00056 
00057 
00058     // Check if the new human pose is far enough from the previous one the justify sending a new waypoint
00059     double human_pose_delta = sqrt(pow(msg->pose.position.x - human_pose.pose.position.x, 2) +
00060                                    pow(msg->pose.position.y - human_pose.pose.position.y, 2));
00061 
00062     if (human_pose_delta > human_pose_delta_threshold) {
00063 
00064         // Filename formatting
00065         boost::posix_time::ptime curr_time = boost::posix_time::second_clock::local_time();
00066         std::string time_str = boost::posix_time::to_iso_extended_string(curr_time);
00067 
00068         wb_path_to_image = directory + "human_following_" + time_str + ".PNG";
00069         wb_image = wb_image_candidate;
00070 
00071         // // Noise protection
00072         // human_pose_candidate_count += 1;
00073         // human_pose_candidate.pose.position = msg->pose.position;
00074 
00075         human_pose.pose.position = msg->pose.position;
00076         human_pose.header.frame_id = "level_mux/map";
00077         human_pose.header.stamp = msg->header.stamp;
00078         human_pose.pose.orientation.x = 0;
00079         human_pose.pose.orientation.y = 0;
00080         human_pose.pose.orientation.z = 0;
00081         human_pose.pose.orientation.w = 1;
00082         // ROS_INFO("Human_pose before (%.2f, %.2f)", human_pose.pose.position.x, human_pose.pose.position.y);
00083 
00084         // Modify the location of the human so that it's slightly off in the direction
00085         // of the robot
00086         human_following_pose = human_pose;
00087         double theta = atan2(human_pose.pose.position.y - current_pose.position.y,
00088                              human_pose.pose.position.x - current_pose.position.x);
00089         // Convert angle to the right range by adding PI? Doesn't feel like this is needed for ROS
00090         human_following_pose.pose.position.x -= human_following_pose_offset * cos(theta);
00091         human_following_pose.pose.position.y -= human_following_pose_offset * sin(theta);
00092         human_following_pose.pose.orientation.x = 0;
00093         human_following_pose.pose.orientation.y = 0;
00094         human_following_pose.pose.orientation.z = sin((theta)/2);
00095         human_following_pose.pose.orientation.w = cos((theta)/2);
00096         human_pose.pose.orientation.x = 0;
00097         human_pose.pose.orientation.y = 0;
00098         human_pose.pose.orientation.z = sin((theta)/2);
00099         human_pose.pose.orientation.w = cos((theta)/2);
00100         // ROS_INFO("human_following_pose after  (%.2f, %.2f)", human_following_pose.pose.position.x, human_following_pose.pose.position.y);
00101 
00102         human_detected = 1;
00103     }
00104 }
00105 
00106 
00107 void ScavTaskHumanFollowing::callback_image(const sensor_msgs::ImageConstPtr& msg)
00108 {
00109     wb_image_candidate = msg;
00110 }
00111 
00112 
00113 void ScavTaskHumanFollowing::callback_ac_followed(const actionlib::SimpleClientGoalState& state,
00114                                                        const move_base_msgs::MoveBaseResultConstPtr& result)
00115 {
00116     ROS_INFO("Reached human following way point");
00117     // Only proceed to move to human's location if the person has not been seen for a fixed duraction
00118     ros::Duration last_detected_duration_threshold (0.2);
00119     ros::Duration detection_time_elapsed = ros::Time::now() - detected_time;
00120     if (detection_time_elapsed < last_detected_duration_threshold){
00121         ROS_INFO("Human still in view, not moving in; detection_elapsed: %f", detection_time_elapsed.toSec());
00122     } else {
00123         ROS_INFO("Move to human's last seen location");
00124         human_detected = 2;
00125     }
00126 }
00127 
00128 void ScavTaskHumanFollowing::callback_ac_reached(const actionlib::SimpleClientGoalState& state,
00129                                                       const move_base_msgs::MoveBaseResultConstPtr& result)
00130 {
00131     ROS_INFO("Reached human last seen location");
00132     human_detected = 4;
00133 }
00134 
00135 void ScavTaskHumanFollowing::callback_ac_done(const actionlib::SimpleClientGoalState& state,
00136                                                  const move_base_msgs::MoveBaseResultConstPtr& result)
00137 {
00138     human_detected = 4;
00139 }
00140 
00141 void ScavTaskHumanFollowing::amclPoseCallback(
00142     const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg) {
00143     current_pose = msg->pose.pose;
00144 }
00145 
00146 void ScavTaskHumanFollowing::motionThread() {
00147 
00148     ros::Rate r(2);
00149 
00150     // Keep track of the robot's current pose
00151     ros::Subscriber amcl_pose_sub;
00152     amcl_pose_sub = nh->subscribe("amcl_pose", 100, &ScavTaskHumanFollowing::amclPoseCallback, this);
00153 
00154     move_base_msgs::MoveBaseGoal goal;
00155     sound_play::SoundRequest sound_msg; 
00156 
00157     // Loop to send action requests
00158     while (ros::ok() and r.sleep() and task_completed == false) {
00159         ros::spinOnce();
00160         ROS_INFO_STREAM("human_detected: " << human_detected); 
00161 
00162         // random visit door until a human's detected
00163         if (human_detected == -1) {
00164             if (false == search_planner_simple->busy) 
00165                 search_planner_simple->moveToNextDoor();   
00166         }
00167 
00168 
00169 
00170         // Set new waypoint if new human is detected
00171         if (human_detected == 1) {
00172  
00173             human_detected = 0;
00174             goal.target_pose = human_following_pose;
00175             ac.sendGoal(goal, boost::bind(&ScavTaskHumanFollowing::callback_ac_followed, this,  _1, _2));
00176 
00177             sound_msg.command = sound_play::SoundRequest::PLAY_ONCE; 
00178             sound_msg.arg = "following"; 
00179             sound_msg.arg2 = "voice_kal_diphone"; 
00180 
00181             sound_pub.publish(sound_msg); 
00182         }
00183         // callback_ac_followed should set the condition to go to human's last seen location
00184         if (human_detected == 2) {
00185             human_detected = 0;
00186             goal.target_pose = human_pose;
00187             ac.sendGoal(goal, boost::bind(&ScavTaskHumanFollowing::callback_ac_reached, this,  _1, _2));
00188         }
00189         // if (human_detected == 3) {
00190         //     // Spin
00191         //     human_detected = 0;
00192         //     geometry_msgs::Twist rotate;
00193         //     rotate.angular.z = -0.4;
00194 
00195         //     ros::Time start_time = ros::Time::now();
00196         //     ros::Duration spin_timeout(4.0); // Timeout of 2 seconds
00197         //     while(ros::Time::now() - start_time < spin_timeout) {
00198         //         cmd_vel_pub.publish(rotate);
00199         //         ros::spinOnce();
00200         //     }
00201         //     goal.target_pose = human_pose;
00202         //     ac.sendGoal(goal, boost::bind(&ScavTaskHumanFollowing::callback_ac_reached, this,  _1, _2));
00203         // }
00204         if (human_detected == 4) {
00205             human_detected = 0;
00206             ROS_INFO("Human lost, following task complete");
00207 
00208             cv_bridge::CvImageConstPtr cv_ptr = cv_bridge::toCvShare(wb_image, sensor_msgs::image_encodings::BGR8);
00209 
00210             if (boost::filesystem::is_directory(directory) == false) {
00211                 boost::filesystem::path tmp_path(directory);
00212                 boost::filesystem::create_directory(tmp_path);
00213             }
00214             ROS_INFO("Saving image at %s", wb_path_to_image.c_str());
00215             cv::imwrite(wb_path_to_image, cv_ptr->image);
00216 
00217             // Scp the log file to remote machine
00218 
00219             // std::string scp_remote_path = "wxie@hypnotoad.csres.utexas.edu:~/bwi_scavenger_log_files/";
00220             // std::string system_string = "scp -P 40 " + wb_path_to_image + " " + scp_remote_path;
00221             // ROS_INFO("%s", system_string.c_str());
00222             // if (system(system_string.c_str()) == -1) {
00223             //     ROS_WARN("Problem transferring log image file to remote machine. Please ssh permission and remote machine");
00224             // }
00225 
00226             // search_planner->setTargetDetection(true); // change status to terminate the motion thread
00227 
00228             ROS_INFO_STREAM("Finished saving image: " << wb_path_to_image); 
00229 
00230             task_completed = true;
00231         }
00232     }
00233 }
00234 
00235 void ScavTaskHumanFollowing::visionThread() {
00236 
00237     ros::Subscriber sub_human = nh->subscribe("/segbot_pcl_person_detector/human_poses",
00238         100, &ScavTaskHumanFollowing::callback_human_detected, this);
00239 
00240     image_transport::ImageTransport it(*nh);
00241     image_transport::Subscriber sub_image = it.subscribe("/nav_kinect/rgb/image_raw",
00242         1, &ScavTaskHumanFollowing::callback_image, this);
00243 
00244     ros::Rate r(10);
00245     while (ros::ok() and r.sleep() and !task_completed) {
00246         ros::spinOnce();
00247     }
00248 }
00249 
00250 void ScavTaskHumanFollowing::executeTask(int timeout, TaskResult &result, std::string &record) {
00251 
00252     boost::thread motion( &ScavTaskHumanFollowing::motionThread, this);
00253     boost::thread vision( &ScavTaskHumanFollowing::visionThread, this);
00254 
00255     motion.join();
00256     vision.join();
00257     record = wb_path_to_image;
00258     result = SUCCEEDED;
00259 }
00260 
00261 
00262 void ScavTaskHumanFollowing::stopEarly() {
00263     task_completed = true; 
00264 }
00265 }


bwi_scavenger
Author(s): Shiqi Zhang
autogenerated on Thu Jun 6 2019 17:57:53