26 #include "../../util/CollisionCheckUtil.h"
32 Task::Task(
const CSpaceBasePtr& cspace,
const VectorXf& startCfg,
const VectorXf& goalCfg,
const std::string& taskName,
float dcdStep,
33 float gridStepSize,
Ice::Long maximalPlanningTimeInSeconds)
35 this->cspace = cspace->clone();
36 this->startCfg = startCfg;
37 this->goalCfg = goalCfg;
38 this->dcdStep = dcdStep;
39 this->gridStepSize = gridStepSize;
40 this->maximalPlanningTimeInSeconds = maximalPlanningTimeInSeconds;
41 this->taskName = taskName;
43 if (startCfg.size() != goalCfg.size() || startCfg.size() !=
static_cast<std::size_t
>(this->cspace->getDimensionality()))
45 throw std::invalid_argument {
"start and goal have to be the size of the cspace's dimensionality"};
48 if (gridStepSize < dcdStep)
50 throw std::invalid_argument {
"the step size of the implicit grid has to be larger than the DCD step size"};
57 std::lock_guard<std::mutex> lock {
mtx};
61 void Task::run(
const RemoteObjectNodePrxList&,
const Ice::Current&)
63 const std::size_t n = cspace->getDimensionality();
67 cspace->initCollisionTest();
69 const auto startIsCollisionFree = cspace->isCollisionFree(std::pair<const Ice::Float*, const Ice::Float*> {startCfg.data(), startCfg.data() + startCfg.size()});
70 const auto goalIscollisionFree = cspace->isCollisionFree(std::pair<const Ice::Float*, const Ice::Float*> { goalCfg.data(), goalCfg.data() + goalCfg.size()});
71 if (!startIsCollisionFree || !goalIscollisionFree)
77 const auto distStartEnd =
euclideanDistance(startCfg.begin(), startCfg.end(), goalCfg.begin());
79 if (distStartEnd <= dcdStep)
82 solution.nodes.emplace_back(startCfg);
83 solution.nodes.emplace_back(goalCfg);
88 using GridPointType = std::vector<long>;
91 LongRangeSeq gridBounds;
92 gridBounds.reserve(n);
93 const auto&& cspaceBounds = cspace->getDimensionsBounds();
95 cspaceBounds.begin(), cspaceBounds.end(), startCfg.begin(), std::back_inserter(gridBounds),
96 [
this](
const FloatRange & dimBounds,
float start)
99 const auto distLower = dimBounds.min - start;
100 const auto gridPointsLower = std::trunc(distLower / gridStepSize);
102 const auto distHigher = dimBounds.max - start;
103 const auto gridPointsHigher = std::trunc(distHigher / gridStepSize);
105 return LongRange {static_cast<Ice::Long>(gridPointsLower), static_cast<Ice::Long>(gridPointsHigher)};
112 auto getNeighbours = [gridBounds, n](
const GridPointType & p)
114 std::vector<GridPointType> neighbours;
116 neighbours.push_back(p);
117 neighbours.reserve(std::pow(3, gridBounds.size()));
118 for (std::size_t i = 0; i < n; ++i)
120 const auto n = neighbours.size();
121 const auto generateLower = (gridBounds.at(i).min < p.at(i));
122 const auto generateHigher = (gridBounds.at(i).max > p.at(i));
123 neighbours.reserve(n * (1 + generateHigher + generateLower));
127 neighbours.begin(), neighbours.begin() + n, std::back_inserter(neighbours),
128 [i](
typename decltype(neighbours)::value_type
v)
138 neighbours.begin(), neighbours.begin() + n, std::back_inserter(neighbours),
139 [i](
typename decltype(neighbours)::value_type
v)
152 auto toConfig = [
this](
const GridPointType & gridPoint)
155 cfg.reserve(gridPoint.size());
157 gridPoint.begin(), gridPoint.end(), startCfg.begin(), std::back_inserter(cfg),
158 [
this](
float g,
float s)
160 return s + g * gridStepSize;
166 auto distance = [](
const GridPointType &
a,
const GridPointType & b)
174 for (std::size_t i = 0; i < n; ++i)
176 auto dist = goalCfg.at(i) - startCfg.at(i);
177 long gridPoint = std::round(dist / gridStepSize);
178 goal.emplace_back(
std::clamp(gridPoint, gridBounds.at(i).min, gridBounds.at(i).max));
180 if (!isPathCollisionFree(goalCfg, toConfig(goal)))
182 setTaskStatus(TaskStatus::ePlanningFailed);
185 setTaskStatus(TaskStatus::eDone);
194 std::size_t predecessor = 0;
197 std::deque<NodeData> nodes;
199 std::set<std::size_t> openSet;
201 nodes.emplace_back();
202 nodes.back().cfg = startCfg;
203 nodes.back().node.assign(n, 0);
206 std::set<std::size_t> closedSet;
208 auto assemblePath = [&](std::size_t toId)
210 std::deque<VectorXf> reversedPath;
211 reversedPath.emplace_back(goalCfg);
214 auto& currentNode = nodes.at(toId);
215 reversedPath.emplace_back(std::move(currentNode.cfg));
216 if (toId == currentNode.predecessor)
220 toId = currentNode.predecessor;
223 path.reserve(reversedPath.size());
224 std::move(reversedPath.rbegin(), reversedPath.rend(), std::back_inserter(path));
228 auto expandNode = [&](std::size_t idToExpand)
230 const auto& toExpand = nodes.at(idToExpand);
231 const auto successors = getNeighbours(toExpand.node);
232 for (std::size_t sucIdx = 1; sucIdx < successors.size(); ++sucIdx)
234 auto& successor = successors.at(sucIdx);
236 auto successorIt = std::find_if(nodes.begin(), nodes.end(), [&](
const NodeData & elem)
238 return successor == elem.node;
240 auto successorId =
std::distance(nodes.begin(), successorIt);
242 if (closedSet.find(successorId) != closedSet.end())
247 float tentativeGScore = toExpand.gScore +
distance(successor, toExpand.node);
249 bool successorIsInOpenSet = openSet.find(successorId) != openSet.end();
250 if (successorIsInOpenSet && tentativeGScore >= successorIt->gScore)
256 auto successorCfg = successorIsInOpenSet ? std::move(successorIt->cfg) : toConfig(successor);
258 if (!isPathCollisionFree(toExpand.cfg, successorCfg))
263 const auto newFScore = tentativeGScore +
distance(successor, goal);
264 if (successorIsInOpenSet)
267 successorIt->cfg = std::move(successorCfg);
268 successorIt->fScore = newFScore;
269 successorIt->gScore = tentativeGScore;
270 successorIt->predecessor = idToExpand;
275 openSet.emplace(nodes.size());
276 nodes.emplace_back();
277 nodes.back().node = std::move(successor);
278 nodes.back().cfg = std::move(successorCfg);
279 nodes.back().fScore = newFScore;
280 nodes.back().gScore = tentativeGScore;
281 nodes.back().predecessor = idToExpand;
287 const auto endTime = std::chrono::system_clock::now() + std::chrono::seconds {maximalPlanningTimeInSeconds};
294 setTaskStatus(TaskStatus::ePlanningAborted);
297 if (endTime < std::chrono::system_clock::now())
299 setTaskStatus(TaskStatus::ePlanningFailed);
305 setTaskStatus(TaskStatus::ePlanningFailed);
308 auto currentIdIt = std::min_element(
309 openSet.begin(), openSet.end(),
310 [&](std::size_t osId1, std::size_t osId2)
312 return nodes.at(osId1).fScore < nodes.at(osId2).fScore;
315 auto currentId = *currentIdIt;
316 openSet.erase(currentIdIt);
318 if (nodes.at(currentId).node == goal)
320 solution.nodes = assemblePath(currentId);
321 setTaskStatus(TaskStatus::eDone);
325 closedSet.emplace(currentId);
326 expandNode(currentId);
332 bool Task::isPathCollisionFree(
const VectorXf& from,
const VectorXf& to)
336 [
this](
const VectorXf & cfg)
338 return cspace->isCollisionFree({cfg.data(), cfg.data() + cfg.size()});