SMACC2
Loading...
Searching...
No Matches
cp_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 <ament_index_cpp/get_package_share_directory.hpp>
25#include <fstream>
33#include <rclcpp/rclcpp.hpp>
34
35namespace cl_nav2z
36{
37using namespace std::chrono_literals;
38CpWaypointNavigatorBase::CpWaypointNavigatorBase() : currentWaypoint_(0), waypoints_(0) {}
39
41
43
45
47
54
61
63{
66 RCLCPP_WARN(
67 getLogger(), "[CpWaypointNavigator] Goal result received, incrementing waypoint index: %ld",
70
71 this->notifyGoalReached();
72
74}
75
77{
80}
81
83{
85 if (currentWaypoint_ >= (long)waypoints_.size() - 1)
86 currentWaypoint_ = (long)waypoints_.size() - 1;
87}
88
90{
91 bool found = false;
92
93 auto previousWaypoint = currentWaypoint_;
94
95 while (!found && currentWaypoint_ < (long)waypoints_.size())
96 {
97 auto & nextName = waypointsNames_[currentWaypoint_];
98 RCLCPP_INFO(
99 getLogger(), "[CpWaypointNavigator] seeking ,%ld/%ld candidate waypoint: %s",
100 currentWaypoint_, waypoints_.size(), nextName.c_str());
101 if (name == nextName)
102 {
103 found = true;
104 RCLCPP_INFO(
105 getLogger(), "[CpWaypointNavigator] found target waypoint: %s == %s-> found",
106 nextName.c_str(), name.c_str());
107 }
108 else
109 {
110 RCLCPP_INFO(
111 getLogger(), "[CpWaypointNavigator] current waypoint: %s != %s -> forward",
112 nextName.c_str(), name.c_str());
114 }
115 }
116
117 if (found)
118 {
119 if (currentWaypoint_ >= (long)waypoints_.size() - 1)
120 currentWaypoint_ = (long)waypoints_.size() - 1;
121 }
122 else // search backwards
123 {
124 currentWaypoint_ = previousWaypoint;
125 while (!found && currentWaypoint_ > 0)
126 {
127 auto & nextName = waypointsNames_[currentWaypoint_];
128 RCLCPP_INFO(
129 getLogger(), "[CpWaypointNavigator] seeking , candidate waypoint: %s", nextName.c_str());
130 if (name == nextName)
131 {
132 found = true;
133 RCLCPP_INFO(
134 getLogger(), "[CpWaypointNavigator] found target waypoint: %s == %s-> found",
135 nextName.c_str(), name.c_str());
136 }
137 else
138 {
139 RCLCPP_INFO(
140 getLogger(), "[CpWaypointNavigator] current waypoint: %s != %s -> rewind",
141 nextName.c_str(), name.c_str());
143 }
144 }
145 }
146
147 RCLCPP_INFO(
148 getLogger(), "[CpWaypointNavigator] seekName( %s), previous index: %ld, after index: %ld",
149 name.c_str(), previousWaypoint, currentWaypoint_);
150}
151
153 std::string parameter_name, std::string yaml_file_package_name)
154{
155 // if it is the first time and the waypoints navigator is not configured
156 std::string planfilepath;
157 planfilepath = getNode()->declare_parameter(parameter_name, planfilepath);
158 RCLCPP_INFO(getLogger(), "waypoints plan parameter: %s", planfilepath.c_str());
159 if (getNode()->get_parameter(parameter_name, planfilepath))
160 {
161 std::string package_share_directory =
162 ament_index_cpp::get_package_share_directory(yaml_file_package_name);
163
164 RCLCPP_INFO(getLogger(), "file macro path: %s", planfilepath.c_str());
165
166 boost::replace_all(planfilepath, "$(pkg_share)", package_share_directory);
167
168 RCLCPP_INFO(getLogger(), "package share path: %s", package_share_directory.c_str());
169 RCLCPP_INFO(getLogger(), "waypoints plan file: %s", planfilepath.c_str());
170
171 this->loadWayPointsFromFile(planfilepath);
172 RCLCPP_INFO(getLogger(), "waypoints plan: %s", planfilepath.c_str());
173 }
174 else
175 {
176 RCLCPP_ERROR(getLogger(), "waypoints plan file not found: NONE");
177 }
178}
179
181{
182 if (succeddedNav2ZClientConnection_.connected())
183 {
184 this->succeddedNav2ZClientConnection_.disconnect();
185 this->cancelledNav2ZClientConnection_.disconnect();
186 this->abortedNav2ZClientConnection_.disconnect();
187 }
188}
189
190std::optional<std::shared_future<
191 std::shared_ptr<rclcpp_action::ClientGoalHandle<nav2_msgs::action::NavigateToPose>>>>
193 std::optional<NavigateNextWaypointOptions> options,
195{
196 if (currentWaypoint_ >= 0 && currentWaypoint_ < (int)waypoints_.size())
197 {
198 auto & next = waypoints_[currentWaypoint_];
199
200 std::string nextName;
201 if ((long)waypointsNames_.size() > currentWaypoint_)
202 {
204 RCLCPP_INFO(
205 getLogger(), "[CpWaypointNavigator] sending goal, waypoint: %s", nextName.c_str());
206 }
207 else
208 {
209 RCLCPP_INFO(
210 getLogger(), "[CpWaypointNavigator] sending goal, waypoint: %ld", currentWaypoint_);
211 }
212
213 ClNav2Z::Goal goal;
215 auto pose = p->toPoseMsg();
216
217 // configuring goal
218 goal.pose.header.frame_id = p->getReferenceFrame();
219 //goal.pose.header.stamp = getNode()->now();
220 goal.pose.pose = next;
221
222 auto plannerSwitcher = client_->getComponent<CpPlannerSwitcher>();
223 plannerSwitcher->setDefaultPlanners(false);
224 if (options && options->controllerName_)
225 {
226 RCLCPP_WARN(
227 getLogger(), "[WaypointsNavigator] override controller: %s",
228 options->controllerName_->c_str());
229
230 plannerSwitcher->setDesiredController(*options->controllerName_);
231 }
232 else
233 {
234 RCLCPP_WARN(getLogger(), "[WaypointsNavigator] Configuring default planners");
235 }
236
237 auto goalCheckerSwitcher = client_->getComponent<CpGoalCheckerSwitcher>();
238
239 if (options && options->goalCheckerName_)
240 {
241 RCLCPP_WARN(
242 getLogger(), "[WaypointsNavigator] override goal checker: %s",
243 options->goalCheckerName_->c_str());
244
245 goalCheckerSwitcher->setGoalCheckerId(*options->goalCheckerName_);
246 }
247 else
248 {
249 RCLCPP_WARN(getLogger(), "[WaypointsNavigator] Configuring default goal checker");
250 goalCheckerSwitcher->setGoalCheckerId("goal_checker");
251 }
252
253 plannerSwitcher->commitPublish();
254
255 // publish stuff
256 // rclcpp::sleep_for(5s);
257
258 RCLCPP_INFO(getLogger(), "[WaypointsNavigator] Getting odom tracker");
260 if (odomTracker != nullptr)
261 {
262 RCLCPP_INFO(getLogger(), "[WaypointsNavigator] Storing path in odom tracker");
263
264 auto pathname = this->owner_->getStateMachine()->getCurrentState()->getName() + " - " +
265 getName() + " - " + nextName;
266 odomTracker->pushPath(pathname);
267 odomTracker->setStartPoint(pose);
268 odomTracker->setWorkingMode(cl_nav2z::odom_tracker::WorkingMode::RECORD_PATH);
269 }
270
271 // SEND GOAL
272 // if (!succeddedNav2ZClientConnection_.connected())
273 // {
274 // this->succeddedNav2ZClientConnection_ =
275 // client_->onSucceeded(&WaypointNavigator::onGoalReached, this);
276 // this->cancelledNav2ZClientConnection_ =
277 // client_->onAborted(&WaypointNavigator::onGoalCancelled, this);
278 // this->abortedNav2ZClientConnection_ =
279 // client_->onCancelled(&WaypointNavigator::onGoalAborted, this);
280 // }
281
282 auto callbackptr = resultCallback.lock();
284 *callbackptr, &CpWaypointNavigator::onNavigationResult, this);
285
286 return client_->sendGoal(goal, resultCallback);
287 }
288 else
289 {
290 RCLCPP_WARN(
291 getLogger(),
292 "[CpWaypointsNavigator] All waypoints were consumed. There is no more waypoints available.");
293 }
294
295 return std::nullopt;
296}
297
299{
300 // when it is the last waypoint post an finalization EOF event
301 if (currentWaypoint_ == (long)waypoints_.size() - 1)
302 {
303 RCLCPP_WARN(getLogger(), "[CpWaypointNavigator] Last waypoint reached, posting EOF event. ");
304 this->postEvent<EvWaypointFinal>();
305 }
306}
307
309{
310 if (r.code == rclcpp_action::ResultCode::SUCCEEDED)
311 {
312 this->onGoalReached(r);
313 }
314 else if (r.code == rclcpp_action::ResultCode::ABORTED)
315 {
316 this->onGoalAborted(r);
317 }
318 else if (r.code == rclcpp_action::ResultCode::CANCELED)
319 {
320 this->onGoalCancelled(r);
321 }
322 else
323 {
324 this->onGoalAborted(r);
325 }
326}
327
328void CpWaypointNavigatorBase::insertWaypoint(int index, geometry_msgs::msg::Pose & newpose)
329{
330 if (index >= 0 && index <= (int)waypoints_.size())
331 {
332 waypoints_.insert(waypoints_.begin(), index, newpose);
333 }
334}
335
336void CpWaypointNavigatorBase::setWaypoints(const std::vector<geometry_msgs::msg::Pose> & waypoints)
337{
338 this->waypoints_ = waypoints;
339}
340
341void CpWaypointNavigatorBase::setWaypoints(const std::vector<Pose2D> & waypoints)
342{
343 waypoints_.clear();
344 waypointsNames_.clear();
345 int i = 0;
346 for (auto & p : waypoints)
347 {
348 geometry_msgs::msg::Pose pose;
349 pose.position.x = p.x_;
350 pose.position.y = p.y_;
351 pose.position.z = 0.0;
352 tf2::Quaternion q;
353 q.setRPY(0, 0, p.yaw_);
354 pose.orientation = tf2::toMsg(q);
355
356 waypoints_.push_back(pose);
357 waypointsNames_.push_back(std::to_string(i++));
358 }
359}
360
362{
363 if (index >= 0 && index < (int)waypoints_.size())
364 {
365 waypoints_.erase(waypoints_.begin() + index);
366 }
367}
368
369const std::vector<geometry_msgs::msg::Pose> & CpWaypointNavigatorBase::getWaypoints() const
370{
371 return waypoints_;
372}
373
374geometry_msgs::msg::Pose CpWaypointNavigatorBase::getPose(int index) const
375{
376 if (index >= 0 && index < (int)waypoints_.size())
377 {
378 return waypoints_[index];
379 }
380 else
381 {
382 throw std::out_of_range("Waypoint index out of range");
383 }
384}
385geometry_msgs::msg::Pose CpWaypointNavigatorBase::getCurrentPose() const
386{
387 if (currentWaypoint_ >= 0 && currentWaypoint_ < (int)waypoints_.size())
388 {
390 }
391 else
392 {
393 throw std::out_of_range("Waypoint index out of range");
394 }
395}
396
397std::optional<geometry_msgs::msg::Pose> CpWaypointNavigatorBase::getNamedPose(
398 std::string name) const
399{
400 if (this->waypointsNames_.size() > 0)
401 {
402 for (int i = 0; i < (int)this->waypointsNames_.size(); i++)
403 {
404 if (this->waypointsNames_[i] == name)
405 {
406 return this->waypoints_[i];
407 }
408 }
409 }
410
411 return std::nullopt;
412}
413
414const std::vector<std::string> & CpWaypointNavigatorBase::getWaypointNames() const
415{
416 return waypointsNames_;
417}
418
419std::optional<std::string> CpWaypointNavigatorBase::getCurrentWaypointName() const
420{
421 if (currentWaypoint_ >= 0 && currentWaypoint_ < (int)waypointsNames_.size())
422 {
424 }
425 return std::nullopt;
426}
427
429
430#define HAVE_NEW_YAMLCPP
432{
433 RCLCPP_INFO_STREAM(getLogger(), "[CpWaypointNavigatorBase] Loading file:" << filepath);
434 this->waypoints_.clear();
435 std::ifstream ifs(filepath.c_str(), std::ifstream::in);
436 if (ifs.good() == false)
437 {
438 throw std::string("Waypoints file not found");
439 }
440
441 try
442 {
443#ifdef HAVE_NEW_YAMLCPP
444 YAML::Node node = YAML::Load(ifs);
445#else
446 YAML::Parser parser(ifs);
447 parser.GetNextDocument(node);
448#endif
449
450#ifdef HAVE_NEW_YAMLCPP
451 const YAML::Node & wp_node_tmp = node["waypoints"];
452 const YAML::Node * wp_node = wp_node_tmp ? &wp_node_tmp : NULL;
453#else
454 const YAML::Node * wp_node = node.FindValue("waypoints");
455#endif
456
457 if (wp_node != NULL)
458 {
459 for (int64_t i = 0; i < wp_node->size(); ++i)
460 {
461 // Parse waypoint entries on YAML
462 geometry_msgs::msg::Pose wp;
463
464 try
465 {
466 // (*wp_node)[i]["name"] >> wp.name;
467 // (*wp_node)[i]["frame_id"] >> wp.header.frame_id;
468
469 auto wpnodei = (*wp_node)[i];
470 wp.position.x = wpnodei["position"]["x"].as<double>();
471 wp.position.y = wpnodei["position"]["y"].as<double>();
472 wp.position.z = wpnodei["position"]["z"].as<double>();
473 wp.orientation.x = wpnodei["orientation"]["x"].as<double>();
474 wp.orientation.y = wpnodei["orientation"]["y"].as<double>();
475 wp.orientation.z = wpnodei["orientation"]["z"].as<double>();
476 wp.orientation.w = wpnodei["orientation"]["w"].as<double>();
477
478 if (wpnodei["name"].IsDefined())
479 {
480 this->waypointsNames_.push_back(wpnodei["name"].as<std::string>());
481 }
482
483 this->waypoints_.push_back(wp);
484 }
485 catch (...)
486 {
487 RCLCPP_ERROR(getLogger(), "parsing waypoint file, syntax error in point %ld", i);
488 }
489 }
490 RCLCPP_INFO_STREAM(getLogger(), "Parsed " << this->waypoints_.size() << " waypoints.");
491 }
492 else
493 {
494 RCLCPP_WARN_STREAM(getLogger(), "Couldn't find any waypoints in the provided yaml file.");
495 }
496 }
497 catch (const YAML::ParserException & ex)
498 {
499 RCLCPP_ERROR_STREAM(
500 getLogger(), "Error loading the Waypoints YAML file. Incorrect syntax: " << ex.what());
501 }
502}
503
505{
506 RCLCPP_INFO_STREAM(getLogger(), "[CpWaypointNavigator] Loading file:" << filepath);
507 this->waypoints_.clear();
508 std::ifstream ifs(filepath.c_str(), std::ifstream::in);
509 if (ifs.good() == false)
510 {
511 throw std::string("Waypoints file not found");
512 }
513
514 try
515 {
516#ifdef HAVE_NEW_YAMLCPP
517 YAML::Node node = YAML::Load(ifs);
518#else
519 YAML::Parser parser(ifs);
520 parser.GetNextDocument(node);
521#endif
522
523#ifdef HAVE_NEW_YAMLCPP
524 const YAML::Node & wp_node_tmp = node["waypoints"];
525 const YAML::Node * wp_node = wp_node_tmp ? &wp_node_tmp : NULL;
526#else
527 const YAML::Node * wp_node = node.FindValue("waypoints");
528#endif
529
530 if (wp_node != NULL)
531 {
532 for (int64_t i = 0; i < wp_node->size(); ++i)
533 {
534 // Parse waypoint entries on YAML
535 geometry_msgs::msg::Pose wp;
536
537 try
538 {
539 // (*wp_node)[i]["name"] >> wp.name;
540 // (*wp_node)[i]["frame_id"] >> wp.header.frame_id;
541 wp.position.x = (*wp_node)[i]["x"].as<double>();
542 wp.position.y = (*wp_node)[i]["y"].as<double>();
543 auto name = (*wp_node)[i]["name"].as<std::string>();
544
545 this->waypoints_.push_back(wp);
546 this->waypointsNames_.push_back(name);
547 }
548 catch (...)
549 {
550 RCLCPP_ERROR(getLogger(), "parsing waypoint file, syntax error in point %ld", i);
551 }
552 }
553 RCLCPP_INFO_STREAM(getLogger(), "Parsed " << this->waypoints_.size() << " waypoints.");
554 }
555 else
556 {
557 RCLCPP_WARN_STREAM(getLogger(), "Couldn't find any waypoints in the provided yaml file.");
558 }
559 }
560 catch (const YAML::ParserException & ex)
561 {
562 RCLCPP_ERROR_STREAM(
563 getLogger(), "Error loading the Waypoints YAML file. Incorrect syntax: " << ex.what());
564 }
565}
566} // namespace cl_nav2z
void setDefaultPlanners(bool commit=true)
void setWaypoints(const std::vector< geometry_msgs::msg::Pose > &waypoints)
const std::vector< geometry_msgs::msg::Pose > & getWaypoints() const
void loadWayPointsFromFile2(std::string filepath)
std::vector< geometry_msgs::msg::Pose > waypoints_
geometry_msgs::msg::Pose getCurrentPose() const
void loadWayPointsFromFile(std::string filepath)
std::optional< std::string > getCurrentWaypointName() const
std::optional< geometry_msgs::msg::Pose > getNamedPose(std::string name) const
geometry_msgs::msg::Pose getPose(int index) const
const std::vector< std::string > & getWaypointNames() const
void loadWaypointsFromYamlParameter(std::string parameter_name, std::string yaml_file_package_name)
void insertWaypoint(int index, geometry_msgs::msg::Pose &newpose)
boost::signals2::connection succeddedNav2ZClientConnection_
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())
boost::signals2::connection abortedNav2ZClientConnection_
smacc2::SmaccSignal< void()> onNavigationRequestCancelled
boost::signals2::connection cancelledNav2ZClientConnection_
void onGoalAborted(const ClNav2Z::WrappedResult &)
void onGoalCancelled(const ClNav2Z::WrappedResult &)
void onNavigationResult(const ClNav2Z::WrappedResult &r)
smacc2::SmaccSignal< void()> onNavigationRequestAborted
smacc2::SmaccSignal< void()> onNavigationRequestSucceded
void onGoalReached(const ClNav2Z::WrappedResult &res)
geometry_msgs::msg::Pose toPoseMsg()
Definition cp_pose.hpp:57
ISmaccStateMachine * getStateMachine()
ISmaccClient * owner_
Definition component.hpp:83
ISmaccStateMachine * getStateMachine()
virtual std::string getName() const
rclcpp::Logger getLogger() const
rclcpp::Node::SharedPtr getNode()
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())