TimedElasticBands.cpp
Go to the documentation of this file.
1 #include "TimedElasticBands.h"
2 
3 #include <filesystem>
4 #include <fstream>
5 #include <memory>
6 #include <optional>
7 #include <string>
8 #include <vector>
9 
10 #include <boost/smart_ptr/make_shared_object.hpp>
11 
12 #include <SimoxUtility/algorithm/apply.hpp>
13 #include <SimoxUtility/color/Color.h>
14 #include <VirtualRobot/CollisionDetection/CollisionModel.h> // IWYU pragma: keep
15 #include <VirtualRobot/Robot.h> // IWYU pragma: keep
16 #include <VirtualRobot/SceneObjectSet.h> // IWYU pragma: keep
17 
23 
27 
34 #include <armarx/navigation/local_planning/aron/TimedElasticBands.aron.generated.h>
38 
39 #include <geometry_msgs/Twist.h>
40 #include <nlohmann/json_fwd.hpp>
41 #include <ros/time.h>
42 #include <teb_local_planner/homotopy_class_planner.h>
43 #include <teb_local_planner/pose_se2.h>
44 #include <teb_local_planner/robot_footprint_model.h>
45 #include <teb_local_planner/timed_elastic_band.h>
46 #include <teb_local_planner/visualization.h>
47 
49 {
50 
51  // TimedElasticBands
52 
53  TimedElasticBands::TimedElasticBands(const Params& i_params, const core::Scene& scene) :
54  LocalPlanner(scene), params(i_params), scene(scene), obstManager(teb_obstacles)
55  {
57  const auto robotName = scene.robot->getName();
58 
59  //TODO (SALt): find proper place to init with default config
60  readConfig(params.cfg, robotName);
61 
62  toTebCfg(params.cfg, cfg_);
63 
64  auto robot_model = boost::make_shared<teb_local_planner::CircularRobotFootprint>(
65  params.cfg.robot_footprint_radius);
66 
67  ARMARX_VERBOSE << "Robot footprint is " << params.cfg.robot_footprint_radius << "m";
68 
69  hcp_ = std::make_unique<teb_local_planner::HomotopyClassPlanner>();
70  hcp_->initialize(
71  cfg_, &teb_obstacles, robot_model, teb_local_planner::TebVisualizationPtr(), nullptr);
72  //set member teb_costmap
73  setTebCostmap();
74  if (teb_costmap)
75  {
76  ARMARX_INFO << "Costmap available.";
77  // TODO: where to put all the parameters
78  const human::ExponentialPenaltyModel penalty{
79  .minDistance = 0.5, .epsilon = 0, .exponent = 1.2};
80 
81  teb_costmap->setPenaltyModel(conv::toRos(penalty));
82  hcp_->setCostmap(&teb_costmap.value());
83  }
84  ros::Time::init(); // we have to init time before we can use the planner
85  }
86 
87  void
88  TimedElasticBands::readConfig(arondto::TimedElasticBandsParams& target,
89  const std::string& robotName)
90  {
91 
92  const armarx::PackagePath configPath = [&]() -> armarx::PackagePath
93  {
94  const armarx::PackagePath robotSpecificConfigPath(
95  "armarx_navigation",
96  "local_planner_config/TimedElasticBands/" + robotName + ".json");
97 
98  if (std::filesystem::exists(robotSpecificConfigPath.toSystemPath()))
99  {
100  ARMARX_INFO << "Using robot-specific config `" << robotSpecificConfigPath << "`.";
101  return robotSpecificConfigPath;
102  }
103 
104  const armarx::PackagePath defaultConfigPath(
105  "armarx_navigation", "local_planner_config/TimedElasticBands/default.json");
106  ARMARX_INFO << "Using default config `" << robotSpecificConfigPath << "`";
107 
108  return defaultConfigPath;
109  }();
110 
111  const std::filesystem::path file = configPath.toSystemPath();
112 
113  ARMARX_CHECK(std::filesystem::is_regular_file(file)) << file;
114 
115  ARMARX_INFO << "Loading config from file `" << file << "`.";
116  std::ifstream ifs{file};
117 
118  nlohmann::json jsonConfig;
119  ifs >> jsonConfig;
120 
121  ARMARX_INFO << "Reading config";
122 
124  target.read(reader, jsonConfig);
125  }
126 
127  std::optional<LocalPlannerResult>
129  {
130  const core::Pose currentPose{scene.robot->getGlobalPose()};
131 
132  // prune global trajectory
133  const auto& [prunedGoal, planToDest] = goal.getSubTrajectory(
134  currentPose.translation(), params.cfg.planning_distance * 1000); // [m] to [mm]
135 
136  const teb_local_planner::TimedElasticBand globalPath = conv::toRos(prunedGoal);
137  teb_globalPath = globalPath.poses();
138  hcp_->setGlobalPath(&teb_globalPath);
139 
140  const teb_local_planner::PoseSE2 start = conv::toRos(currentPose);
141  const teb_local_planner::PoseSE2 end =
142  conv::toRos(prunedGoal.points().back().waypoint.pose);
143 
144  geometry_msgs::Twist velocity_start = conv::toRos(scene.platformVelocity);
145 
146 
147  fillObstacles();
148 
149  bool success;
150  try
151  {
152  success = hcp_->plan(start, end, &velocity_start, !planToDest);
153  }
154  catch (...)
155  {
156  hcp_->clearPlanner();
157  ARMARX_ERROR << "Caugth exception while planning: " << GetHandledExceptionString();
158  return std::nullopt;
159  }
160 
162  ARMARX_INFO << VAROUT(hcp_->hasDiverged());
163 
164  if (!success)
165  {
166  ARMARX_INFO << "Found trajectory is not feasible!";
167  hcp_->clearPlanner();
168  ARMARX_WARNING << deactivateSpam(5) << "Found trajectory is not feasible!";
169  return std::nullopt;
170  }
171 
172  if (false && hcp_->hasDiverged())
173  //if (hcp_->hasDiverged())
174  {
175  hcp_->clearPlanner();
176  ARMARX_WARNING << /*deactivateSpam(5) << */ "Planner has diverged!";
177  return std::nullopt;
178  }
179 
180  if (hcp_->getTrajectoryContainer().empty())
181  {
182  hcp_->clearPlanner();
183  ARMARX_INFO << "Did not find any trajectory!";
184  return std::nullopt;
185  }
186 
187  ARMARX_VERBOSE << "Planned successfully (found " << hcp_->getTrajectoryContainer().size()
188  << " Trajectories)";
189 
190  core::LocalTrajectory best = conv::fromRos(hcp_->findBestTeb()->teb());
191 
192  // visualize path alternatives
193  if (arviz)
194  {
195  auto layer = arviz.value().layer("local_planner_path_alternatives");
196 
197  int i = 0;
198  int bestTebIdx = hcp_->bestTebIdx();
199  for (const auto& teb : hcp_->getTrajectoryContainer())
200  {
201  if (i == bestTebIdx)
202  {
203  continue;
204  }
205  const core::LocalTrajectory trajectory = conv::fromRos(teb->teb());
206  const std::vector<Eigen::Vector3f> points =
207  simox::alg::apply(trajectory.points(),
208  [](const core::LocalTrajectoryPoint& pt) -> Eigen::Vector3f
209  { return pt.pose.translation(); });
210  layer.add(viz::Path("path_alternative_" + std::to_string(i))
211  .points(points)
212  .color(simox::Color::gray()));
213  i++;
214  }
215 
216  arviz.value().commit(layer);
217  }
218 
219  return {{.trajectory = best}};
220  }
221 
222  void
223  TimedElasticBands::fillObstacles()
224  {
225  obstManager.clear();
226 
227  viz::Layer* visPtr = nullptr;
228  viz::Layer visLayer;
229  if (arviz)
230  {
231  visLayer = arviz.value().layer("local_planner_obstacles");
232  visPtr = &visLayer;
233  }
234 
235 
236  if (scene.staticScene)
237  {
238  ARMARX_CHECK(scene.staticScene.has_value());
239  for (const auto& obst : scene.staticScene.value().objects->getCollisionModels())
240  {
241  obstManager.addBoxObstacle(obst->getGlobalBoundingBox(), visPtr);
242  }
243  }
244  if (scene.dynamicScene)
245  {
246  ARMARX_CHECK(scene.dynamicScene.has_value());
247  for (const auto& obst : scene.dynamicScene.value().humans)
248  {
249  obstManager.addHumanObstacle(obst, visPtr);
250  }
251 
252  for (const auto& obst : scene.dynamicScene->laserScannerFeatures)
253  {
254  obstManager.addLaserScannerFeaturesObstacle(obst, visPtr);
255  }
256  }
257 
258  if (arviz)
259  {
260  arviz.value().commit(visLayer);
261  }
262 
263  ARMARX_VERBOSE << "TEB: added " << obstManager.size() << " obstacles";
264  }
265 
266  //export algorithms::Costmap to costmap type of teb local planner and provide costmap to planner
267  void
268  TimedElasticBands::setTebCostmap()
269  {
270  if (not scene.staticScene.has_value())
271  {
272  return;
273  }
274 
275  if (not scene.staticScene->distanceToObstaclesCostmap.has_value())
276  {
277  return;
278  }
279 
280  return;
281 
282  const algorithms::Costmap& navigationCostmap =
283  scene.staticScene->distanceToObstaclesCostmap.value();
284  teb_costmap.emplace(conv::toRos(navigationCostmap));
285  }
286 
287 } // namespace armarx::navigation::local_planning
armarx::navigation::core::GlobalTrajectory
Definition: Trajectory.h:70
armarx::navigation::core::Scene::robot
VirtualRobot::RobotPtr robot
Definition: types.h:67
TimedElasticBands.h
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::navigation::human::ExponentialPenaltyModel::minDistance
float minDistance
Definition: types.h:70
armarx::navigation::local_planning::TebObstacleManager::addBoxObstacle
void addBoxObstacle(const VirtualRobot::BoundingBox &bbox, viz::Layer *visLayer=nullptr)
Definition: TebObstacleManager.cpp:71
armarx::navigation::local_planning::LocalPlanner::arviz
std::optional< viz::ScopedClient > arviz
Definition: LocalPlanner.h:64
Path.h
armarx::navigation::core::Scene::staticScene
std::optional< core::StaticScene > staticScene
Definition: types.h:64
LocalException.h
armarx::navigation::core::Pose
Eigen::Isometry3f Pose
Definition: basic_types.h:31
basic_types.h
NlohmannJSONReaderWithoutTypeCheck.h
ARMARX_CHECK_NOT_NULL
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
Definition: ExpressionException.h:206
LocalPlanner.h
armarx::navigation::human::ExponentialPenaltyModel
Definition: types.h:68
boost::target
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
Definition: point_cloud_graph.h:668
armarx::navigation::local_planning::TimedElasticBands::TimedElasticBands
TimedElasticBands(const Params &params, const core::Scene &scene)
Definition: TimedElasticBands.cpp:53
Layer.h
types.h
armarx::navigation::local_planning
This file is part of ArmarX.
Definition: fwd.h:35
armarx::navigation::conv::fromRos
Eigen::Vector3f fromRos(const Eigen::Vector2d &vec)
Definition: ros_conversions.cpp:49
aron_conversions_teb.h
armarx::navigation::core::LocalTrajectory::points
const std::vector< LocalTrajectoryPoint > & points() const
Definition: Trajectory.cpp:839
StringHelpers.h
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::navigation::local_planning::TimedElasticBandsParams::cfg
arondto::TimedElasticBandsParams cfg
Definition: TimedElasticBandsParams.h:36
Costmap.h
armarx::navigation::core::Scene::platformVelocity
core::Twist platformVelocity
Definition: types.h:68
armarx::navigation::core::LocalTrajectoryPoint
Definition: Trajectory.h:156
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:75
armarx::GetHandledExceptionString
std::string GetHandledExceptionString()
Definition: Exception.cpp:165
armarx::navigation::core::GlobalTrajectory::getSubTrajectory
std::pair< GlobalTrajectory, bool > getSubTrajectory(const Position &point, const float distance) const
Project point onto the trajectory and return a new trajectory along the old one from that point for t...
Definition: Trajectory.cpp:289
armarx::PackagePath::toSystemPath
static std::filesystem::path toSystemPath(const data::PackagePath &pp)
Definition: PackagePath.cpp:47
armarx::aron::data::reader::NlohmannJSONReaderWithoutTypeCheck
Definition: NlohmannJSONReaderWithoutTypeCheck.h:35
armarx::navigation::local_planning::TimedElasticBandsParams
Definition: TimedElasticBandsParams.h:34
armarx::navigation::conv::toRos
Eigen::Vector2d toRos(const Eigen::Vector3f &vec)
Definition: ros_conversions.cpp:43
armarx::navigation::core::LocalTrajectory
Definition: Trajectory.h:170
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::navigation::core::Scene
Definition: types.h:60
armarx::navigation::core::Scene::dynamicScene
std::optional< core::DynamicScene > dynamicScene
Definition: types.h:65
ExpressionException.h
armarx::navigation::local_planning::TebObstacleManager::clear
void clear()
Definition: TebObstacleManager.cpp:16
armarx::navigation::local_planning::TimedElasticBands::plan
std::optional< LocalPlannerResult > plan(const core::GlobalTrajectory &goal) override
Definition: TimedElasticBands.cpp:128
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
armarx::navigation::local_planning::TebObstacleManager::size
size_t size()
Definition: TebObstacleManager.cpp:23
armarx::navigation::local_planning::TebObstacleManager::addLaserScannerFeaturesObstacle
void addLaserScannerFeaturesObstacle(const memory::LaserScannerFeatures &features, viz::Layer *visLayer=nullptr)
Definition: TebObstacleManager.cpp:29
armarx::navigation::local_planning::toTebCfg
void toTebCfg(const arondto::TimedElasticBandsParams &dto, ::teb_local_planner::TebConfig &bo)
Definition: aron_conversions_teb.cpp:11
armarx::navigation::local_planning::TebObstacleManager::addHumanObstacle
void addHumanObstacle(const human::Human &human, viz::Layer *visLayer=nullptr)
Definition: TebObstacleManager.cpp:86
armarx::navigation::local_planning::LocalPlanner
Definition: LocalPlanner.h:53
Logging.h
armarx::navigation::local_planning::TimedElasticBands::params
Params params
Definition: TimedElasticBands.h:58
armarx::viz::Path
Definition: Path.h:31
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
Trajectory.h
armarx::PackagePath
Definition: PackagePath.h:52
armarx::viz::Layer
Definition: Layer.h:12
types.h
armarx::status::success
@ success
aron_conversions.h
ros_conversions.h
PackagePath.h