SMACC2
Loading...
Searching...
No Matches
waypoints_navigator.cpp
Go to the documentation of this file.
1// Copyright 2021 RobosoftAI Inc.
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/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#include <tf2/transform_datatypes.h>
22#include <yaml-cpp/yaml.h>
23
24#include <fstream>
32#include <rclcpp/rclcpp.hpp>
33
34namespace cl_nav2z
35{
36using namespace std::chrono_literals;
37WaypointNavigator::WaypointNavigator() : currentWaypoint_(0), waypoints_(0) {}
38
40
42{
44
46}
47
49{
51
53}
54
56{
59 RCLCPP_WARN(
60 getLogger(), "[WaypointNavigator] Goal result received, incrementing waypoint index: %ld",
63
65}
66
67void WaypointNavigator::rewind(int /*count*/)
68{
71}
72
74{
76 if (currentWaypoint_ >= (long)waypoints_.size() - 1)
77 currentWaypoint_ = (long)waypoints_.size() - 1;
78}
79
80void WaypointNavigator::seekName(std::string name)
81{
82 bool found = false;
83
84 auto previousWaypoint = currentWaypoint_;
85
86 while (!found && currentWaypoint_ < (long)waypoints_.size())
87 {
88 auto & nextName = waypointsNames_[currentWaypoint_];
89 RCLCPP_INFO(
90 getLogger(), "[WaypointNavigator] seeking ,%ld/%ld candidate waypoint: %s", currentWaypoint_,
91 waypoints_.size(), nextName.c_str());
92 if (name == nextName)
93 {
94 found = true;
95 RCLCPP_INFO(
96 getLogger(), "[WaypointNavigator] found target waypoint: %s == %s-> found",
97 nextName.c_str(), name.c_str());
98 }
99 else
100 {
101 RCLCPP_INFO(
102 getLogger(), "[WaypointNavigator] current waypoint: %s != %s -> forward", nextName.c_str(),
103 name.c_str());
105 }
106 }
107
108 if (found)
109 {
110 if (currentWaypoint_ >= (long)waypoints_.size() - 1)
111 currentWaypoint_ = (long)waypoints_.size() - 1;
112 }
113 else // search backwards
114 {
115 currentWaypoint_ = previousWaypoint;
116 while (!found && currentWaypoint_ > 0)
117 {
118 auto & nextName = waypointsNames_[currentWaypoint_];
119 RCLCPP_INFO(
120 getLogger(), "[WaypointNavigator] seeking , candidate waypoint: %s", nextName.c_str());
121 if (name == nextName)
122 {
123 found = true;
124 RCLCPP_INFO(
125 getLogger(), "[WaypointNavigator] found target waypoint: %s == %s-> found",
126 nextName.c_str(), name.c_str());
127 }
128 else
129 {
130 RCLCPP_INFO(
131 getLogger(), "[WaypointNavigator] current waypoint: %s != %s -> rewind", nextName.c_str(),
132 name.c_str());
134 }
135 }
136 }
137
138 RCLCPP_INFO(
139 getLogger(), "[WaypointNavigator] seekName( %s), previous index: %ld, after index: %ld",
140 name.c_str(), previousWaypoint, currentWaypoint_);
141}
142
144{
145 if (succeddedNav2ZClientConnection_.connected())
146 {
147 this->succeddedNav2ZClientConnection_.disconnect();
148 this->cancelledNav2ZClientConnection_.disconnect();
149 this->abortedNav2ZClientConnection_.disconnect();
150 }
151}
152
153std::optional<std::shared_future<
154 std::shared_ptr<rclcpp_action::ClientGoalHandle<nav2_msgs::action::NavigateToPose>>>>
156 std::optional<NavigateNextWaypointOptions> options,
158{
159 if (currentWaypoint_ >= 0 && currentWaypoint_ < (int)waypoints_.size())
160 {
161 auto & next = waypoints_[currentWaypoint_];
162
163 std::string nextName;
164 if ((long)waypointsNames_.size() > currentWaypoint_)
165 {
167 RCLCPP_INFO(getLogger(), "[WaypointNavigator] sending goal, waypoint: %s", nextName.c_str());
168 }
169 else
170 {
171 RCLCPP_INFO(getLogger(), "[WaypointNavigator] sending goal, waypoint: %ld", currentWaypoint_);
172 }
173
174 ClNav2Z::Goal goal;
176 auto pose = p->toPoseMsg();
177
178 // configuring goal
179 goal.pose.header.frame_id = p->getReferenceFrame();
180 //goal.pose.header.stamp = getNode()->now();
181 goal.pose.pose = next;
182
183 auto plannerSwitcher = client_->getComponent<PlannerSwitcher>();
184 plannerSwitcher->setDefaultPlanners(false);
185 if (options && options->controllerName_)
186 {
187 RCLCPP_WARN(
188 getLogger(), "[WaypointsNavigator] override controller: %s",
189 options->controllerName_->c_str());
190
191 plannerSwitcher->setDesiredController(*options->controllerName_);
192 }
193 else
194 {
195 RCLCPP_WARN(getLogger(), "[WaypointsNavigator] Configuring default planners");
196 }
197
198 auto goalCheckerSwitcher = client_->getComponent<GoalCheckerSwitcher>();
199
200 if (options && options->goalCheckerName_)
201 {
202 RCLCPP_WARN(
203 getLogger(), "[WaypointsNavigator] override goal checker: %s",
204 options->goalCheckerName_->c_str());
205
206 goalCheckerSwitcher->setGoalCheckerId(*options->goalCheckerName_);
207 }
208 else
209 {
210 RCLCPP_WARN(getLogger(), "[WaypointsNavigator] Configuring default goal checker");
211 goalCheckerSwitcher->setGoalCheckerId("goal_checker");
212 }
213
214 plannerSwitcher->commitPublish();
215
216 // publish stuff
217 // rclcpp::sleep_for(5s);
218
219 RCLCPP_INFO(getLogger(), "[WaypointsNavigator] Getting odom tracker");
221 if (odomTracker != nullptr)
222 {
223 RCLCPP_INFO(getLogger(), "[WaypointsNavigator] Storing path in odom tracker");
224
225 auto pathname = this->owner_->getStateMachine()->getCurrentState()->getName() + " - " +
226 getName() + " - " + nextName;
227 odomTracker->pushPath(pathname);
228 odomTracker->setStartPoint(pose);
229 odomTracker->setWorkingMode(cl_nav2z::odom_tracker::WorkingMode::RECORD_PATH);
230 }
231
232 // SEND GOAL
233 // if (!succeddedNav2ZClientConnection_.connected())
234 // {
235 // this->succeddedNav2ZClientConnection_ =
236 // client_->onSucceeded(&WaypointNavigator::onGoalReached, this);
237 // this->cancelledNav2ZClientConnection_ =
238 // client_->onAborted(&WaypointNavigator::onGoalCancelled, this);
239 // this->abortedNav2ZClientConnection_ =
240 // client_->onCancelled(&WaypointNavigator::onGoalAborted, this);
241 // }
242
243 auto callbackptr = resultCallback.lock();
245 *callbackptr, &WaypointNavigator::onNavigationResult, this);
246
247 return client_->sendGoal(goal, resultCallback);
248 //return client_->sendGoal(goal);
249 }
250 else
251 {
252 RCLCPP_WARN(
253 getLogger(),
254 "[WaypointsNavigator] All waypoints were consumed. There is no more waypoints available.");
255 }
256
257 return std::nullopt;
258}
259
261{
262 if (r.code == rclcpp_action::ResultCode::SUCCEEDED)
263 {
264 this->onGoalReached(r);
265 }
266 else if (r.code == rclcpp_action::ResultCode::ABORTED)
267 {
268 this->onGoalAborted(r);
269 }
270 else if (r.code == rclcpp_action::ResultCode::CANCELED)
271 {
272 this->onGoalCancelled(r);
273 }
274 else
275 {
276 this->onGoalAborted(r);
277 }
278}
279
280void WaypointNavigator::insertWaypoint(int index, geometry_msgs::msg::Pose & newpose)
281{
282 if (index >= 0 && index <= (int)waypoints_.size())
283 {
284 waypoints_.insert(waypoints_.begin(), index, newpose);
285 }
286}
287
288void WaypointNavigator::setWaypoints(const std::vector<geometry_msgs::msg::Pose> & waypoints)
289{
290 this->waypoints_ = waypoints;
291}
292
293void WaypointNavigator::setWaypoints(const std::vector<Pose2D> & waypoints)
294{
295 waypoints_.clear();
296 waypointsNames_.clear();
297 int i = 0;
298 for (auto & p : waypoints)
299 {
300 geometry_msgs::msg::Pose pose;
301 pose.position.x = p.x_;
302 pose.position.y = p.y_;
303 pose.position.z = 0.0;
304 tf2::Quaternion q;
305 q.setRPY(0, 0, p.yaw_);
306 pose.orientation = tf2::toMsg(q);
307
308 waypoints_.push_back(pose);
309 waypointsNames_.push_back(std::to_string(i++));
310 }
311}
312
314{
315 if (index >= 0 && index < (int)waypoints_.size())
316 {
317 waypoints_.erase(waypoints_.begin() + index);
318 }
319}
320
321const std::vector<geometry_msgs::msg::Pose> & WaypointNavigator::getWaypoints() const
322{
323 return waypoints_;
324}
325
326std::optional<geometry_msgs::msg::Pose> WaypointNavigator::getNamedPose(std::string name) const
327{
328 if (this->waypointsNames_.size() > 0)
329 {
330 for (int i = 0; i < (int)this->waypointsNames_.size(); i++)
331 {
332 if (this->waypointsNames_[i] == name)
333 {
334 return this->waypoints_[i];
335 }
336 }
337 }
338
339 return std::nullopt;
340}
341
342const std::vector<std::string> & WaypointNavigator::getWaypointNames() const
343{
344 return waypointsNames_;
345}
346
347std::optional<std::string> WaypointNavigator::getCurrentWaypointName() const
348{
349 if (currentWaypoint_ >= 0 && currentWaypoint_ < (int)waypointsNames_.size())
350 {
352 }
353 return std::nullopt;
354}
355
357
358#define HAVE_NEW_YAMLCPP
360{
361 RCLCPP_INFO_STREAM(getLogger(), "[WaypointNavigator] Loading file:" << filepath);
362 this->waypoints_.clear();
363 std::ifstream ifs(filepath.c_str(), std::ifstream::in);
364 if (ifs.good() == false)
365 {
366 throw std::string("Waypoints file not found");
367 }
368
369 try
370 {
371#ifdef HAVE_NEW_YAMLCPP
372 YAML::Node node = YAML::Load(ifs);
373#else
374 YAML::Parser parser(ifs);
375 parser.GetNextDocument(node);
376#endif
377
378#ifdef HAVE_NEW_YAMLCPP
379 const YAML::Node & wp_node_tmp = node["waypoints"];
380 const YAML::Node * wp_node = wp_node_tmp ? &wp_node_tmp : NULL;
381#else
382 const YAML::Node * wp_node = node.FindValue("waypoints");
383#endif
384
385 if (wp_node != NULL)
386 {
387 for (uint64_t i = 0; i < wp_node->size(); ++i)
388 {
389 // Parse waypoint entries on YAML
390 geometry_msgs::msg::Pose wp;
391
392 try
393 {
394 // (*wp_node)[i]["name"] >> wp.name;
395 // (*wp_node)[i]["frame_id"] >> wp.header.frame_id;
396
397 auto wpnodei = (*wp_node)[i];
398 wp.position.x = wpnodei["position"]["x"].as<double>();
399 wp.position.y = wpnodei["position"]["y"].as<double>();
400 wp.position.z = wpnodei["position"]["z"].as<double>();
401 wp.orientation.x = wpnodei["orientation"]["x"].as<double>();
402 wp.orientation.y = wpnodei["orientation"]["y"].as<double>();
403 wp.orientation.z = wpnodei["orientation"]["z"].as<double>();
404 wp.orientation.w = wpnodei["orientation"]["w"].as<double>();
405
406 if (wpnodei["name"].IsDefined())
407 {
408 this->waypointsNames_.push_back(wpnodei["name"].as<std::string>());
409 }
410
411 this->waypoints_.push_back(wp);
412 }
413 catch (...)
414 {
415 RCLCPP_ERROR(getLogger(), "parsing waypoint file, syntax error in point %ld", i);
416 }
417 }
418 RCLCPP_INFO_STREAM(getLogger(), "Parsed " << this->waypoints_.size() << " waypoints.");
419 }
420 else
421 {
422 RCLCPP_WARN_STREAM(getLogger(), "Couldn't find any waypoints in the provided yaml file.");
423 }
424 }
425 catch (const YAML::ParserException & ex)
426 {
427 RCLCPP_ERROR_STREAM(
428 getLogger(), "Error loading the Waypoints YAML file. Incorrect syntax: " << ex.what());
429 }
430}
431
433{
434 RCLCPP_INFO_STREAM(getLogger(), "[WaypointNavigator] Loading file:" << filepath);
435 this->waypoints_.clear();
436 std::ifstream ifs(filepath.c_str(), std::ifstream::in);
437 if (ifs.good() == false)
438 {
439 throw std::string("Waypoints file not found");
440 }
441
442 try
443 {
444#ifdef HAVE_NEW_YAMLCPP
445 YAML::Node node = YAML::Load(ifs);
446#else
447 YAML::Parser parser(ifs);
448 parser.GetNextDocument(node);
449#endif
450
451#ifdef HAVE_NEW_YAMLCPP
452 const YAML::Node & wp_node_tmp = node["waypoints"];
453 const YAML::Node * wp_node = wp_node_tmp ? &wp_node_tmp : NULL;
454#else
455 const YAML::Node * wp_node = node.FindValue("waypoints");
456#endif
457
458 if (wp_node != NULL)
459 {
460 for (uint64_t i = 0; i < wp_node->size(); ++i)
461 {
462 // Parse waypoint entries on YAML
463 geometry_msgs::msg::Pose wp;
464
465 try
466 {
467 // (*wp_node)[i]["name"] >> wp.name;
468 // (*wp_node)[i]["frame_id"] >> wp.header.frame_id;
469 wp.position.x = (*wp_node)[i]["x"].as<double>();
470 wp.position.y = (*wp_node)[i]["y"].as<double>();
471 auto name = (*wp_node)[i]["name"].as<std::string>();
472
473 this->waypoints_.push_back(wp);
474 this->waypointsNames_.push_back(name);
475 }
476 catch (...)
477 {
478 RCLCPP_ERROR(getLogger(), "parsing waypoint file, syntax error in point %ld", i);
479 }
480 }
481 RCLCPP_INFO_STREAM(getLogger(), "Parsed " << this->waypoints_.size() << " waypoints.");
482 }
483 else
484 {
485 RCLCPP_WARN_STREAM(getLogger(), "Couldn't find any waypoints in the provided yaml file.");
486 }
487 }
488 catch (const YAML::ParserException & ex)
489 {
490 RCLCPP_ERROR_STREAM(
491 getLogger(), "Error loading the Waypoints YAML file. Incorrect syntax: " << ex.what());
492 }
493}
494} // namespace cl_nav2z
void setDefaultPlanners(bool commit=true)
geometry_msgs::msg::Pose toPoseMsg()
Definition: cp_pose.hpp:57
boost::signals2::connection cancelledNav2ZClientConnection_
void loadWayPointsFromFile2(std::string filepath)
void onGoalCancelled(const ClNav2Z::WrappedResult &)
std::optional< geometry_msgs::msg::Pose > getNamedPose(std::string name) const
const std::vector< geometry_msgs::msg::Pose > & getWaypoints() const
boost::signals2::connection abortedNav2ZClientConnection_
std::vector< std::string > waypointsNames_
void onNavigationResult(const ClNav2Z::WrappedResult &r)
WaypointEventDispatcher waypointsEventDispatcher
boost::signals2::connection succeddedNav2ZClientConnection_
smacc2::SmaccSignal< void()> onNavigationRequestCancelled
void onGoalReached(const ClNav2Z::WrappedResult &res)
std::optional< std::shared_future< std::shared_ptr< rclcpp_action::ClientGoalHandle< nav2_msgs::action::NavigateToPose > > > > sendNextGoal(std::optional< NavigateNextWaypointOptions > options=std::nullopt, cl_nav2z::ClNav2Z::SmaccNavigateResultSignal::WeakPtr callback=cl_nav2z::ClNav2Z::SmaccNavigateResultSignal::WeakPtr())
smacc2::SmaccSignal< void()> onNavigationRequestAborted
std::vector< geometry_msgs::msg::Pose > waypoints_
void seekName(std::string name)
void loadWayPointsFromFile(std::string filepath)
const std::vector< std::string > & getWaypointNames() const
std::optional< std::string > getCurrentWaypointName() const
void onGoalAborted(const ClNav2Z::WrappedResult &)
smacc2::SmaccSignal< void()> onNavigationRequestSucceded
void setWaypoints(const std::vector< geometry_msgs::msg::Pose > &waypoints)
void insertWaypoint(int index, geometry_msgs::msg::Pose &newpose)
ISmaccStateMachine * getStateMachine()
TComponent * getComponent()
ISmaccClient * owner_
Definition: component.hpp:83
ISmaccStateMachine * getStateMachine()
virtual std::string getName() const
rclcpp::Logger getLogger() const
boost::signals2::connection createSignalConnection(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object)
virtual std::string getName()=0
std::weak_ptr< SmaccSignal< void(const WrappedResult &), optional_last_value< typename boost::function_traits< void(const WrappedResult &) >::result_type >, int, std::less< int >, function< void(const WrappedResult &) >, typename extended_signature< function_traits< void(const WrappedResult &) >::arity, void(const WrappedResult &) >::function_type, boost::signals2::mutex > > WeakPtr
std::shared_future< typename GoalHandle::SharedPtr > sendGoal(Goal &goal, typename SmaccActionResultSignal::WeakPtr resultCallback=typename SmaccActionResultSignal::WeakPtr())