loop_closure_assistant.cpp
Go to the documentation of this file.
1 /*
2  * loop_closure_assistant
3  * Copyright (c) 2019, Samsung Research America
4  *
5  * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
6  * COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
7  * COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
8  * AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
9  *
10  * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO
11  * BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS
12  * CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
13  * CONDITIONS.
14  *
15  */
16 
17 /* Author: Steven Macenski */
18 
20 
21 namespace loop_closure_assistant
22 {
23 
24 /*****************************************************************************/
26  ros::NodeHandle& node,
27  karto::Mapper* mapper,
28  laser_utils::ScanHolder* scan_holder,
29  PausedState& state, ProcessType & processor_type)
30 : mapper_(mapper), scan_holder_(scan_holder),
31  interactive_mode_(false), nh_(node), state_(state),
32  processor_type_(processor_type)
33 /*****************************************************************************/
34 {
35  node.setParam("paused_processing", false);
36  tfB_ = std::make_unique<tf2_ros::TransformBroadcaster>();
37  ssClear_manual_ = node.advertiseService("clear_changes",
39  ssLoopClosure_ = node.advertiseService("manual_loop_closure",
41  scan_publisher_ = node.advertise<sensor_msgs::LaserScan>(
42  "karto_scan_visualization",10);
45  std::make_unique<interactive_markers::InteractiveMarkerServer>(
46  "slam_toolbox","",true);
47  ssInteractive_ = node.advertiseService("toggle_interactive_mode",
49  node.setParam("interactive_mode", interactive_mode_);
50  marker_publisher_ = node.advertise<visualization_msgs::MarkerArray>(
51  "karto_graph_visualization",1);
52  node.param("map_frame", map_frame_, std::string("map"));
53  node.param("enable_interactive_mode", enable_interactive_mode_, false);
54 }
55 
56 /*****************************************************************************/
58 /*****************************************************************************/
59 {
60  mapper_ = mapper;
61 }
62 
63 /*****************************************************************************/
65  visualization_msgs::InteractiveMarkerFeedbackConstPtr& feedback)
66 /*****************************************************************************/
67 {
68  if (processor_type_ != PROCESS)
69  {
71  "Interactive mode is invalid outside processing mode.");
72  return;
73  }
74 
75  const int id = std::stoi(feedback->marker_name, nullptr, 10) - 1;
76 
77  // was depressed, something moved, and now released
78  if (feedback->event_type ==
79  visualization_msgs::InteractiveMarkerFeedback::MOUSE_UP &&
80  feedback->mouse_point_valid)
81  {
82  addMovedNodes(id, Eigen::Vector3d(feedback->mouse_point.x,
83  feedback->mouse_point.y, tf2::getYaw(feedback->pose.orientation)));
84  }
85 
86  // is currently depressed, being moved before release
87  if (feedback->event_type ==
88  visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE)
89  {
90  // get scan
91  sensor_msgs::LaserScan scan = scan_holder_->getCorrectedScan(id);
92 
93  // get correct orientation
94  tf2::Quaternion quat(0.,0.,0.,1.0), msg_quat(0.,0.,0.,1.0);
95  double node_yaw, first_node_yaw;
96  solver_->GetNodeOrientation(id, node_yaw);
97  solver_->GetNodeOrientation(0, first_node_yaw);
98  tf2::Quaternion q1(0.,0.,0.,1.0);
99  q1.setEuler(0., 0., node_yaw - 3.14159);
100  tf2::Quaternion q2(0.,0.,0.,1.0);
101  q2.setEuler(0., 0., 3.14159);
102  quat *= q1;
103  quat *= q2;
104 
105  // interactive move
106  tf2::convert(feedback->pose.orientation, msg_quat);
107  quat *= msg_quat;
108  quat.normalize();
109 
110  // create correct transform
111  tf2::Transform transform;
112  transform.setOrigin(tf2::Vector3(feedback->pose.position.x,
113  feedback->pose.position.y, 0.));
114  transform.setRotation(quat);
115 
116  // publish the scan visualization with transform
117  geometry_msgs::TransformStamped msg;
118  tf2::convert(transform, msg.transform);
119  msg.child_frame_id = "karto_scan_visualization";
120  msg.header.frame_id = feedback->header.frame_id;
121  msg.header.stamp = ros::Time::now();
122  tfB_->sendTransform(msg);
123 
124  scan.header.frame_id = "karto_scan_visualization";
125  scan.header.stamp = ros::Time::now();
126  scan_publisher_.publish(scan);
127  }
128 }
129 
130 /*****************************************************************************/
132 /*****************************************************************************/
133 {
134  interactive_server_->clear();
135  karto::MapperGraph * graph = mapper_->GetGraph();
136 
137  if (!graph || graph->GetVertices().empty())
138  {
139  return;
140  }
141 
142  using ConstVertexMapIterator =
143  karto::MapperGraph::VertexMap::const_iterator;
144  const karto::MapperGraph::VertexMap& vertices = graph->GetVertices();
145 
146  int graph_size = 0;
147  for (ConstVertexMapIterator it = vertices.begin(); it != vertices.end(); ++it)
148  {
149  graph_size += it->second.size();
150  }
151  ROS_DEBUG("Graph size: %i", graph_size);
152 
153  bool interactive_mode = false;
154  {
155  boost::mutex::scoped_lock lock(interactive_mutex_);
156  interactive_mode = interactive_mode_;
157  }
158 
159  const size_t current_marker_count = marker_array_.markers.size();
160  marker_array_.markers.clear(); // restart the marker count
161 
162  visualization_msgs::Marker vertex_marker =
163  vis_utils::toVertexMarker(map_frame_, "slam_toolbox", 0.1);
164 
165  for (ConstVertexMapIterator outer_it = vertices.begin();
166  outer_it != vertices.end(); ++outer_it)
167  {
168  using ConstVertexMapValueIterator =
169  karto::MapperGraph::VertexMap::mapped_type::const_iterator;
170  for (ConstVertexMapValueIterator inner_it = outer_it->second.begin();
171  inner_it != outer_it->second.end(); ++inner_it)
172  {
173  karto::LocalizedRangeScan * scan = inner_it->second->GetObject();
174 
175  vertex_marker.pose.position.x = scan->GetCorrectedPose().GetX();
176  vertex_marker.pose.position.y = scan->GetCorrectedPose().GetY();
177 
178  if (interactive_mode && enable_interactive_mode_)
179  {
180  // need a 1-to-1 mapping between marker IDs and
181  // scan unique IDs to process interactive feedback
182  vertex_marker.id = scan->GetUniqueId() + 1;
183  visualization_msgs::InteractiveMarker int_marker =
184  vis_utils::toInteractiveMarker(vertex_marker, 0.3);
185  interactive_server_->insert(int_marker,
186  boost::bind(
188  this, _1));
189  }
190  else
191  {
192  // use monotonically increasing vertex marker IDs to
193  // make room for edge marker IDs
194  vertex_marker.id = marker_array_.markers.size();
195  marker_array_.markers.push_back(vertex_marker);
196  }
197  }
198  }
199 
200  if (!interactive_mode)
201  {
202  using EdgeList = std::vector<karto::Edge<karto::LocalizedRangeScan>*>;
203  using ConstEdgeListIterator = EdgeList::const_iterator;
204 
205  visualization_msgs::Marker edge_marker =
206  vis_utils::toEdgeMarker(map_frame_, "slam_toolbox", 0.05);
207 
208  const EdgeList& edges = graph->GetEdges();
209  for (ConstEdgeListIterator it = edges.begin(); it != edges.end(); ++it)
210  {
211  const karto::Edge<karto::LocalizedRangeScan> * edge = *it;
212  karto::LocalizedRangeScan * source_scan = edge->GetSource()->GetObject();
213  karto::LocalizedRangeScan * target_scan = edge->GetTarget()->GetObject();
214  const karto::Pose2 source_pose = source_scan->GetCorrectedPose();
215  const karto::Pose2 target_pose = target_scan->GetCorrectedPose();
216 
217  edge_marker.id = marker_array_.markers.size();
218  edge_marker.points[0].x = source_pose.GetX();
219  edge_marker.points[0].y = source_pose.GetY();
220  edge_marker.points[1].x = target_pose.GetX();
221  edge_marker.points[1].y = target_pose.GetY();
222  marker_array_.markers.push_back(edge_marker);
223  }
224  }
225 
226  const size_t next_marker_count = marker_array_.markers.size();
227 
228  // append preexisting markers to force deletion
229  while (marker_array_.markers.size() < current_marker_count)
230  {
231  visualization_msgs::Marker deleted_marker;
232  deleted_marker.id = marker_array_.markers.size();
233  deleted_marker.action = visualization_msgs::Marker::DELETE;
234  marker_array_.markers.push_back(deleted_marker);
235  }
236 
237  // if disabled, clears out old markers
238  interactive_server_->applyChanges();
240 
241  // drop trailing deleted markers
242  marker_array_.markers.resize(next_marker_count);
243  return;
244 }
245 
246 /*****************************************************************************/
248  slam_toolbox_msgs::LoopClosure::Request& req,
249  slam_toolbox_msgs::LoopClosure::Response& resp)
250 /*****************************************************************************/
251 {
253  {
254  ROS_WARN("Called manual loop closure"
255  " with interactive mode disabled. Ignoring.");
256  return false;
257  }
258 
259  {
260  boost::mutex::scoped_lock lock(moved_nodes_mutex_);
261 
262  if (moved_nodes_.size() == 0)
263  {
264  ROS_WARN("No moved nodes to attempt manual loop closure.");
265  return true;
266  }
267 
268  ROS_INFO("LoopClosureAssistant: Attempting to manual "
269  "loop close with %i moved nodes.", (int)moved_nodes_.size());
270  // for each in node map
271  std::map<int, Eigen::Vector3d>::const_iterator it = moved_nodes_.begin();
272  for (it; it != moved_nodes_.end(); ++it)
273  {
274  moveNode(it->first,
275  Eigen::Vector3d(it->second(0),it->second(1), it->second(2)));
276  }
277  }
278 
279  // optimize
281 
282  // update visualization and clear out nodes completed
283  publishGraph();
284  clearMovedNodes();
285  return true;
286 }
287 
288 /*****************************************************************************/
290  slam_toolbox_msgs::ToggleInteractive::Request &req,
291  slam_toolbox_msgs::ToggleInteractive::Response &resp)
292 /*****************************************************************************/
293 {
295  {
296  ROS_WARN("Called toggle interactive mode with "
297  "interactive mode disabled. Ignoring.");
298  return false;
299  }
300 
301  bool interactive_mode;
302  {
303  boost::mutex::scoped_lock lock_i(interactive_mutex_);
305  interactive_mode = interactive_mode_;
306  nh_.setParam("interactive_mode", interactive_mode_);
307  }
308 
309  ROS_INFO("SlamToolbox: Toggling %s interactive mode.",
310  interactive_mode ? "on" : "off");
311  publishGraph();
312  clearMovedNodes();
313 
314  // set state so we don't overwrite changes in rviz while loop closing
315  state_.set(PROCESSING, interactive_mode);
316  state_.set(VISUALIZING_GRAPH, interactive_mode);
317  nh_.setParam("paused_processing", interactive_mode);
318  return true;
319 }
320 
321 /*****************************************************************************/
323  const int& id, const Eigen::Vector3d& pose)
324 /*****************************************************************************/
325 {
326  solver_->ModifyNode(id, pose);
327 }
328 
329 /*****************************************************************************/
331  slam_toolbox_msgs::Clear::Request& req,
332  slam_toolbox_msgs::Clear::Response& resp)
333 /*****************************************************************************/
334 {
336  {
337  ROS_WARN("Called Clear changes with interactive mode disabled. Ignoring.");
338  return false;
339  }
340 
341  ROS_INFO("LoopClosureAssistant: Clearing manual loop closure nodes.");
342  publishGraph();
343  clearMovedNodes();
344  return true;
345 }
346 
347 /*****************************************************************************/
349 /*****************************************************************************/
350 {
351  boost::mutex::scoped_lock lock(moved_nodes_mutex_);
352  moved_nodes_.clear();
353 }
354 
355 /*****************************************************************************/
356 void LoopClosureAssistant::addMovedNodes(const int& id, Eigen::Vector3d vec)
357 /*****************************************************************************/
358 {
359  ROS_INFO("LoopClosureAssistant: Node %i new manual loop closure "
360  "pose has been recorded.",id);
361  boost::mutex::scoped_lock lock(moved_nodes_mutex_);
362  moved_nodes_[id] = vec;
363 }
364 
365 } // end namespace
ROS_ERROR_THROTTLE
#define ROS_ERROR_THROTTLE(period,...)
karto::Mapper
Definition: Mapper.h:1928
loop_closure_assistant::LoopClosureAssistant::publishGraph
void publishGraph()
Definition: loop_closure_assistant.cpp:131
tf2::convert
void convert(const A &a, B &b)
loop_closure_assistant::LoopClosureAssistant::mapper_
karto::Mapper * mapper_
Definition: loop_closure_assistant.hpp:65
ros::NodeHandle::setParam
void setParam(const std::string &key, bool b) const
toolbox_types::PROCESS
@ PROCESS
Definition: toolbox_types.hpp:86
loop_closure_assistant::LoopClosureAssistant::enable_interactive_mode_
bool enable_interactive_mode_
Definition: loop_closure_assistant.hpp:70
karto::Mapper::GetGraph
virtual MapperGraph * GetGraph() const
Definition: Mapper.cpp:3331
tf2::getYaw
double getYaw(const A &a)
laser_utils::ScanHolder::getCorrectedScan
sensor_msgs::LaserScan getCorrectedScan(const int &id)
Definition: laser_utils.cpp:175
karto::Pose2::GetY
kt_double GetY() const
Definition: Karto.h:2117
karto::Mapper::CorrectPoses
void CorrectPoses()
Definition: Mapper.h:2071
tf2::Transform::setRotation
TF2SIMD_FORCE_INLINE void setRotation(const Quaternion &q)
loop_closure_assistant::LoopClosureAssistant::moved_nodes_mutex_
boost::mutex moved_nodes_mutex_
Definition: loop_closure_assistant.hpp:63
karto::ScanSolver::ModifyNode
virtual void ModifyNode(const int &unique_id, Eigen::Vector3d pose)
Definition: Mapper.h:1035
loop_closure_assistant::LoopClosureAssistant::scan_holder_
laser_utils::ScanHolder * scan_holder_
Definition: loop_closure_assistant.hpp:60
ros::NodeHandle::advertiseService
ServiceServer advertiseService(AdvertiseServiceOptions &ops)
loop_closure_assistant::LoopClosureAssistant::setMapper
void setMapper(karto::Mapper *mapper)
Definition: loop_closure_assistant.cpp:57
tf2::Quaternion::normalize
Quaternion & normalize()
karto::LocalizedRangeScan
Definition: Karto.h:5505
loop_closure_assistant::LoopClosureAssistant::marker_array_
visualization_msgs::MarkerArray marker_array_
Definition: loop_closure_assistant.hpp:68
laser_utils::ScanHolder
Definition: laser_utils.hpp:91
loop_closure_assistant::LoopClosureAssistant::moveNode
void moveNode(const int &id, const Eigen::Vector3d &pose)
Definition: loop_closure_assistant.cpp:322
loop_closure_assistant::LoopClosureAssistant::marker_publisher_
ros::Publisher marker_publisher_
Definition: loop_closure_assistant.hpp:61
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
karto::Graph< LocalizedRangeScan >::VertexMap
std::map< Name, std::map< int, Vertex< LocalizedRangeScan > * > > VertexMap
Definition: Mapper.h:567
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
loop_closure_assistant::LoopClosureAssistant::scan_publisher_
ros::Publisher scan_publisher_
Definition: loop_closure_assistant.hpp:61
loop_closure_assistant::LoopClosureAssistant::LoopClosureAssistant
LoopClosureAssistant(ros::NodeHandle &node, karto::Mapper *mapper, laser_utils::ScanHolder *scan_holder, PausedState &state, ProcessType &processor_type)
Definition: loop_closure_assistant.cpp:25
loop_closure_assistant::LoopClosureAssistant::ssLoopClosure_
ros::ServiceServer ssLoopClosure_
Definition: loop_closure_assistant.hpp:62
loop_closure_assistant::LoopClosureAssistant::tfB_
std::unique_ptr< tf2_ros::TransformBroadcaster > tfB_
Definition: loop_closure_assistant.hpp:59
karto::Vertex::GetObject
T * GetObject() const
Definition: Mapper.h:319
loop_closure_assistant::LoopClosureAssistant::nh_
ros::NodeHandle & nh_
Definition: loop_closure_assistant.hpp:71
loop_closure_assistant::LoopClosureAssistant::clearMovedNodes
void clearMovedNodes()
Definition: loop_closure_assistant.cpp:348
karto::MapperGraph
Definition: Mapper.h:713
ROS_DEBUG
#define ROS_DEBUG(...)
loop_closure_assistant::LoopClosureAssistant::interactiveModeCallback
bool interactiveModeCallback(slam_toolbox_msgs::ToggleInteractive::Request &req, slam_toolbox_msgs::ToggleInteractive::Response &resp)
Definition: loop_closure_assistant.cpp:289
loop_closure_assistant::LoopClosureAssistant::processor_type_
ProcessType & processor_type_
Definition: loop_closure_assistant.hpp:74
tf2::Transform::setOrigin
TF2SIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
karto::Mapper::getScanSolver
ScanSolver * getScanSolver()
Definition: Mapper.cpp:3326
karto::Graph::GetVertices
const VertexMap & GetVertices() const
Definition: Mapper.h:674
loop_closure_assistant::LoopClosureAssistant::interactive_mutex_
boost::mutex interactive_mutex_
Definition: loop_closure_assistant.hpp:69
tf2::Transform
loop_closure_assistant::LoopClosureAssistant::clearChangesCallback
bool clearChangesCallback(slam_toolbox_msgs::Clear::Request &req, slam_toolbox_msgs::Clear::Response &resp)
Definition: loop_closure_assistant.cpp:330
ROS_WARN
#define ROS_WARN(...)
karto::LocalizedRangeScan::GetCorrectedPose
const Pose2 & GetCorrectedPose() const
Definition: Karto.h:5562
loop_closure_assistant::LoopClosureAssistant::addMovedNodes
void addMovedNodes(const int &id, Eigen::Vector3d vec)
Definition: loop_closure_assistant.cpp:356
loop_closure_assistant::LoopClosureAssistant::ssClear_manual_
ros::ServiceServer ssClear_manual_
Definition: loop_closure_assistant.hpp:62
loop_closure_assistant::LoopClosureAssistant::processInteractiveFeedback
void processInteractiveFeedback(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
Definition: loop_closure_assistant.cpp:64
vis_utils::toVertexMarker
visualization_msgs::Marker toVertexMarker(const std::string &frame, const std::string &ns, const double &scale)
Definition: visualization_utils.hpp:25
karto::Graph::GetEdges
const std::vector< Edge< T > * > & GetEdges() const
Definition: Mapper.h:665
vis_utils::toInteractiveMarker
visualization_msgs::InteractiveMarker toInteractiveMarker(visualization_msgs::Marker &marker, const double &scale)
Definition: visualization_utils.hpp:78
loop_closure_assistant::LoopClosureAssistant::map_frame_
std::string map_frame_
Definition: loop_closure_assistant.hpp:72
toolbox_types::PROCESSING
@ PROCESSING
Definition: toolbox_types.hpp:78
karto::Edge::GetTarget
Vertex< T > * GetTarget() const
Definition: Mapper.h:448
karto::SensorData::GetUniqueId
kt_int32s GetUniqueId() const
Definition: Karto.h:5163
loop_closure_assistant::LoopClosureAssistant::interactive_server_
std::unique_ptr< interactive_markers::InteractiveMarkerServer > interactive_server_
Definition: loop_closure_assistant.hpp:67
loop_closure_assistant::LoopClosureAssistant::interactive_mode_
bool interactive_mode_
Definition: loop_closure_assistant.hpp:70
karto::ScanSolver::GetNodeOrientation
virtual void GetNodeOrientation(const int &unique_id, double &pose)
Definition: Mapper.h:1042
tf2::Quaternion::setEuler
void setEuler(const tf2Scalar &yaw, const tf2Scalar &pitch, const tf2Scalar &roll)
karto::Pose2::GetX
kt_double GetX() const
Definition: Karto.h:2099
loop_closure_assistant::LoopClosureAssistant::manualLoopClosureCallback
bool manualLoopClosureCallback(slam_toolbox_msgs::LoopClosure::Request &req, slam_toolbox_msgs::LoopClosure::Response &resp)
Definition: loop_closure_assistant.cpp:247
loop_closure_assistant::LoopClosureAssistant::state_
PausedState & state_
Definition: loop_closure_assistant.hpp:73
ros::NodeHandle::param
T param(const std::string &param_name, const T &default_val) const
tf2::Quaternion
loop_closure_assistant.hpp
karto::Pose2
Definition: Karto.h:2046
loop_closure_assistant
Definition: loop_closure_assistant.hpp:37
toolbox_types::VISUALIZING_GRAPH
@ VISUALIZING_GRAPH
Definition: toolbox_types.hpp:79
toolbox_types::ProcessType
ProcessType
Definition: toolbox_types.hpp:84
loop_closure_assistant::LoopClosureAssistant::moved_nodes_
std::map< int, Eigen::Vector3d > moved_nodes_
Definition: loop_closure_assistant.hpp:64
ROS_INFO
#define ROS_INFO(...)
karto::Edge::GetSource
Vertex< T > * GetSource() const
Definition: Mapper.h:439
loop_closure_assistant::LoopClosureAssistant::solver_
karto::ScanSolver * solver_
Definition: loop_closure_assistant.hpp:66
karto::Edge
Definition: Mapper.h:247
ros::NodeHandle
vis_utils::toEdgeMarker
visualization_msgs::Marker toEdgeMarker(const std::string &frame, const std::string &ns, const double &width)
Definition: visualization_utils.hpp:51
ros::Time::now
static Time now()
loop_closure_assistant::LoopClosureAssistant::ssInteractive_
ros::ServiceServer ssInteractive_
Definition: loop_closure_assistant.hpp:62


slam_toolbox
Author(s): Steve Macenski
autogenerated on Thu Jan 11 2024 03:37:55