29 #include "../../util/CollisionCheckUtil.h"
34 const VectorXf& startCfg,
35 const VectorXf& goalCfg,
36 const std::string& taskName,
41 this->cspace = cspace->clone();
42 this->startCfg = startCfg;
43 this->goalCfg = goalCfg;
44 this->dcdStep = dcdStep;
45 this->gridStepSize = gridStepSize;
46 this->maximalPlanningTimeInSeconds = maximalPlanningTimeInSeconds;
47 this->taskName = taskName;
49 if (startCfg.size() != goalCfg.size() ||
50 startCfg.size() !=
static_cast<std::size_t
>(this->cspace->getDimensionality()))
52 throw std::invalid_argument{
53 "start and goal have to be the size of the cspace's dimensionality"};
56 if (gridStepSize < dcdStep)
58 throw std::invalid_argument{
59 "the step size of the implicit grid has to be larger than the DCD step size"};
66 std::lock_guard<std::mutex> lock{
mtx};
71 Task::run(
const RemoteObjectNodePrxList&,
const Ice::Current&)
73 const std::size_t n = cspace->getDimensionality();
77 cspace->initCollisionTest();
79 const auto startIsCollisionFree =
80 cspace->isCollisionFree(std::pair<const Ice::Float*, const Ice::Float*>{
81 startCfg.data(), startCfg.data() + startCfg.size()});
82 const auto goalIscollisionFree =
83 cspace->isCollisionFree(std::pair<const Ice::Float*, const Ice::Float*>{
84 goalCfg.data(), goalCfg.data() + goalCfg.size()});
85 if (!startIsCollisionFree || !goalIscollisionFree)
91 const auto distStartEnd =
94 if (distStartEnd <= dcdStep)
97 solution.nodes.emplace_back(startCfg);
98 solution.nodes.emplace_back(goalCfg);
103 using GridPointType = std::vector<long>;
106 LongRangeSeq gridBounds;
107 gridBounds.reserve(n);
108 const auto&& cspaceBounds = cspace->getDimensionsBounds();
112 std::back_inserter(gridBounds),
113 [
this](
const FloatRange& dimBounds,
float start)
115 const auto distLower = dimBounds.min - start;
116 const auto gridPointsLower = std::trunc(distLower / gridStepSize);
118 const auto distHigher = dimBounds.max - start;
119 const auto gridPointsHigher = std::trunc(distHigher / gridStepSize);
121 return LongRange{static_cast<Ice::Long>(gridPointsLower),
122 static_cast<Ice::Long>(gridPointsHigher)};
127 auto getNeighbours = [gridBounds, n](
const GridPointType& p)
129 std::vector<GridPointType> neighbours;
131 neighbours.push_back(p);
132 neighbours.reserve(std::pow(3, gridBounds.size()));
133 for (std::size_t i = 0; i < n; ++i)
135 const auto n = neighbours.size();
136 const auto generateLower = (gridBounds.at(i).min < p.at(i));
137 const auto generateHigher = (gridBounds.at(i).max > p.at(i));
139 n * (1 + generateHigher + generateLower));
143 neighbours.begin() + n,
144 std::back_inserter(neighbours),
145 [i](
typename decltype(neighbours)::value_type
v)
154 neighbours.begin() + n,
155 std::back_inserter(neighbours),
156 [i](
typename decltype(neighbours)::value_type
v)
168 auto toConfig = [
this](
const GridPointType& gridPoint)
171 cfg.reserve(gridPoint.size());
175 std::back_inserter(cfg),
176 [
this](
float g,
float s) { return s + g * gridStepSize; });
180 auto distance = [](
const GridPointType&
a,
const GridPointType& b)
186 for (std::size_t i = 0; i < n; ++i)
188 auto dist = goalCfg.at(i) - startCfg.at(i);
189 long gridPoint = std::round(dist / gridStepSize);
190 goal.emplace_back(
std::clamp(gridPoint, gridBounds.at(i).min, gridBounds.at(i).max));
192 if (!isPathCollisionFree(goalCfg, toConfig(goal)))
194 setTaskStatus(TaskStatus::ePlanningFailed);
197 setTaskStatus(TaskStatus::eDone);
206 std::size_t predecessor = 0;
210 std::deque<NodeData> nodes;
212 std::set<std::size_t> openSet;
214 nodes.emplace_back();
215 nodes.back().cfg = startCfg;
216 nodes.back().node.assign(n, 0);
219 std::set<std::size_t> closedSet;
221 auto assemblePath = [&](std::size_t toId)
223 std::deque<VectorXf> reversedPath;
224 reversedPath.emplace_back(goalCfg);
227 auto& currentNode = nodes.at(toId);
228 reversedPath.emplace_back(std::move(currentNode.cfg));
229 if (toId == currentNode.predecessor)
233 toId = currentNode.predecessor;
236 path.reserve(reversedPath.size());
237 std::move(reversedPath.rbegin(), reversedPath.rend(), std::back_inserter(path));
241 auto expandNode = [&](std::size_t idToExpand)
243 const auto& toExpand = nodes.at(idToExpand);
244 const auto successors =
245 getNeighbours(toExpand.node);
246 for (std::size_t sucIdx = 1; sucIdx < successors.size(); ++sucIdx)
248 auto& successor = successors.at(sucIdx);
251 std::find_if(nodes.begin(),
253 [&](
const NodeData& elem) { return successor == elem.node; });
254 auto successorId =
std::distance(nodes.begin(), successorIt);
256 if (closedSet.find(successorId) != closedSet.end())
261 float tentativeGScore = toExpand.gScore +
distance(successor, toExpand.node);
263 bool successorIsInOpenSet = openSet.find(successorId) != openSet.end();
264 if (successorIsInOpenSet && tentativeGScore >= successorIt->gScore)
271 successorIsInOpenSet ? std::move(successorIt->cfg) : toConfig(successor);
273 if (!isPathCollisionFree(toExpand.cfg, successorCfg))
278 const auto newFScore = tentativeGScore +
distance(successor, goal);
279 if (successorIsInOpenSet)
282 successorIt->cfg = std::move(successorCfg);
283 successorIt->fScore = newFScore;
284 successorIt->gScore = tentativeGScore;
285 successorIt->predecessor = idToExpand;
290 openSet.emplace(nodes.size());
291 nodes.emplace_back();
292 nodes.back().node = std::move(successor);
293 nodes.back().cfg = std::move(successorCfg);
294 nodes.back().fScore = newFScore;
295 nodes.back().gScore = tentativeGScore;
296 nodes.back().predecessor = idToExpand;
303 std::chrono::system_clock::now() + std::chrono::seconds{maximalPlanningTimeInSeconds};
310 setTaskStatus(TaskStatus::ePlanningAborted);
313 if (endTime < std::chrono::system_clock::now())
315 setTaskStatus(TaskStatus::ePlanningFailed);
321 setTaskStatus(TaskStatus::ePlanningFailed);
325 std::min_element(openSet.begin(),
327 [&](std::size_t osId1, std::size_t osId2)
328 { return nodes.at(osId1).fScore < nodes.at(osId2).fScore; });
329 auto currentId = *currentIdIt;
330 openSet.erase(currentIdIt);
332 if (nodes.at(currentId).node == goal)
334 solution.nodes = assemblePath(currentId);
335 setTaskStatus(TaskStatus::eDone);
339 closedSet.emplace(currentId);
340 expandNode(currentId);
346 Task::isPathCollisionFree(
const VectorXf& from,
const VectorXf& to)
352 [
this](
const VectorXf& cfg) {
353 return cspace->isCollisionFree({cfg.data(), cfg.data() + cfg.size()});