Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
photo_at_waypoint.cpp
1 // Copyright (c) 2020 Fetullah Atas
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "nav2_waypoint_follower/plugins/photo_at_waypoint.hpp"
16 
17 #include <string>
18 #include <memory>
19 
20 #include "pluginlib/class_list_macros.hpp"
21 
22 #include "nav2_ros_common/node_utils.hpp"
23 
24 namespace nav2_waypoint_follower
25 {
27 {
28 }
29 
31 {
32 }
33 
35  const nav2::LifecycleNode::WeakPtr & parent,
36  const std::string & plugin_name)
37 {
38  auto node = parent.lock();
39 
40  curr_frame_msg_ = std::make_shared<sensor_msgs::msg::Image>();
41 
42  std::string save_dir_as_string;
43  save_dir_as_string = node->declare_or_get_parameter(
44  plugin_name + ".save_dir", std::string("/tmp/waypoint_images"));
45  image_topic_ = node->declare_or_get_parameter(
46  plugin_name + ".image_topic", std::string("/camera/color/image_raw"));
47  image_format_ = node->declare_or_get_parameter(
48  plugin_name + ".image_format", std::string("png"));
49  is_enabled_ = node->declare_or_get_parameter(
50  plugin_name + ".enabled", true);
51 
52  // get inputted save directory and make sure it exists, if not log and create it
53  save_dir_ = save_dir_as_string;
54  try {
55  if (!std::filesystem::exists(save_dir_)) {
56  RCLCPP_WARN(
57  logger_,
58  "Provided save directory for photo at waypoint plugin does not exist,"
59  "provided directory is: %s, the directory will be created automatically.",
60  save_dir_.c_str()
61  );
62  if (!std::filesystem::create_directory(save_dir_)) {
63  RCLCPP_ERROR(
64  logger_,
65  "Failed to create directory!: %s required by photo at waypoint plugin, "
66  "exiting the plugin with failure!",
67  save_dir_.c_str()
68  );
69  is_enabled_ = false;
70  }
71  }
72  } catch (const std::exception & e) {
73  RCLCPP_ERROR(
74  logger_, "Exception (%s) thrown while attempting to create image capture directory."
75  " This task executor is being disabled as it cannot save images.", e.what());
76  is_enabled_ = false;
77  }
78 
79  if (!is_enabled_) {
80  RCLCPP_INFO(
81  logger_, "Photo at waypoint plugin is disabled.");
82  } else {
83  RCLCPP_INFO(
84  logger_, "Initializing photo at waypoint plugin, subscribing to camera topic named; %s",
85  image_topic_.c_str());
86  camera_image_subscriber_ = node->create_subscription<sensor_msgs::msg::Image>(
87  image_topic_,
88  std::bind(&PhotoAtWaypoint::imageCallback, this, std::placeholders::_1));
89  }
90 }
91 
93  const geometry_msgs::msg::PoseStamped & curr_pose, const int & curr_waypoint_index)
94 {
95  if (!is_enabled_) {
96  RCLCPP_WARN(
97  logger_,
98  "Photo at waypoint plugin is disabled. Not performing anything"
99  );
100  return true;
101  }
102  try {
103  // construct the full path to image filename
104  std::filesystem::path file_name = std::to_string(
105  curr_waypoint_index) + "_" +
106  std::to_string(curr_pose.header.stamp.sec) + "." + image_format_;
107  std::filesystem::path full_path_image_path = save_dir_ / file_name;
108 
109  // save the taken photo at this waypoint to given directory
110  std::lock_guard<std::mutex> guard(global_mutex_);
111  cv::Mat curr_frame_mat;
112  deepCopyMsg2Mat(curr_frame_msg_, curr_frame_mat);
113  cv::imwrite(full_path_image_path.string().c_str(), curr_frame_mat);
114  RCLCPP_INFO(
115  logger_,
116  "Photo has been taken successfully at waypoint %i", curr_waypoint_index);
117  } catch (const std::exception & e) {
118  RCLCPP_ERROR(
119  logger_,
120  "Couldn't take photo at waypoint %i! Caught exception: %s \n"
121  "Make sure that the image topic named: %s is valid and active!",
122  curr_waypoint_index,
123  e.what(), image_topic_.c_str());
124  return false;
125  }
126  return true;
127 }
128 
129 void PhotoAtWaypoint::imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr & msg)
130 {
131  std::lock_guard<std::mutex> guard(global_mutex_);
132  curr_frame_msg_ = msg;
133 }
134 
136  const sensor_msgs::msg::Image::ConstSharedPtr & msg,
137  cv::Mat & mat)
138 {
139  cv_bridge::CvImageConstPtr cv_bridge_ptr = cv_bridge::toCvShare(msg, msg->encoding);
140  cv::Mat frame = cv_bridge_ptr->image;
141  if (msg->encoding == "rgb8") {
142  cv::cvtColor(frame, frame, cv::COLOR_RGB2BGR);
143  }
144  frame.copyTo(mat);
145 }
146 
147 } // namespace nav2_waypoint_follower
148 PLUGINLIB_EXPORT_CLASS(
Base class for creating a plugin in order to perform a specific task at waypoint arrivals.
static void deepCopyMsg2Mat(const sensor_msgs::msg::Image::ConstSharedPtr &msg, cv::Mat &mat)
given a shared pointer to sensor::msg::Image type, make a deep copy to inputted cv Mat
bool processAtWaypoint(const geometry_msgs::msg::PoseStamped &curr_pose, const int &curr_waypoint_index)
Override this to define the body of your task that you would like to execute once the robot arrived t...
void imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr &msg)
void initialize(const nav2::LifecycleNode::WeakPtr &parent, const std::string &plugin_name)
declares and loads parameters used
PhotoAtWaypoint()
Construct a new Photo At Waypoint object.
~PhotoAtWaypoint()
Destroy the Photo At Waypoint object.