CalcPath.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2014-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package RobotSkillTemplates::MovePlatformToLandmarkGroup
19  * @author Valerij Wittenbeck ( valerij dot wittenbeck at student dot kit dot edu )
20  * @date 2014
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #include "CalcPath.h"
26 
30 
31 #include <VirtualRobot/MathTools.h>
34 
35 #include "../PlatformContext.h"
36 
37 
38 using namespace armarx;
39 using namespace PlatformGroup;
40 
41 // DO NOT EDIT NEXT LINE
42 CalcPath::SubClassRegistry CalcPath::Registry(CalcPath::GetName(), &CalcPath::CreateInstance);
43 
44 
45 
47  XMLStateTemplate<CalcPath>(stateData),
48  CalcPathGeneratedBase<CalcPath>(stateData)
49 {
50  ARMARX_IMPORTANT << "CalcPath";
51 }
52 
54  const ::memoryx::GraphNodeBaseList& nodes, float currentX, float currentY,
55  Eigen::Vector2f& closest, memoryx::GraphNodePtr& edgeNode1, memoryx::GraphNodePtr& edgeNode2)
56 {
57  Eigen::Vector2f robotLocation(currentX, currentY);
58  closest.setZero();
59 
60  for (auto& basenode : nodes)
61  {
62  memoryx::GraphNodePtr node = memoryx::GraphNodePtr::dynamicCast(basenode);
63 
64  auto size = node->getOutdegree();
65  for (int i = 0; i < size; ++i)
66  {
67  memoryx::GraphNodePtr nextNode = memoryx::GraphNodePtr::dynamicCast(node->getAdjacentNode(i)->getEntity());
68 
69  Eigen::Vector2f node1 = FramedPosePtr::dynamicCast(node->getPose())->toEigen().block<2, 1>(0, 3);
70  Eigen::Vector2f node2 = FramedPosePtr::dynamicCast(nextNode->getPose())->toEigen().block<2, 1>(0, 3);
71 
72  if ((node1 - node2).norm() > 1e-9)
73  {
74  Eigen::Vector2f result = VirtualRobot::MathTools::nearestPointOnSegment<Eigen::Vector2f>(node1, node2, robotLocation);
75 
76  if ((closest.x() == 0 && closest.y() == 0) || (result - robotLocation).norm() < (closest - robotLocation).norm())
77  {
78  closest = result;
79  edgeNode1 = node;
80  edgeNode2 = nextNode;
81  }
82  }
83  }
84  }
85 
86  return (closest.x() != 0 || closest.y() != 0);
87 }
88 
89 /**
90  * @brief Projection of point on an edge of the graph.
91  * (node)-------(position)-------->(targetNode)
92  */
94 {
96  Eigen::Vector2f position;
97 };
98 
99 std::vector<EdgeProjection> getNearestPositionOnEdges(const ::memoryx::GraphNodeBaseList& nodes, Eigen::Vector2f robotPos)
100 {
101  std::vector<EdgeProjection> projections;
102 
103  for (auto& basenode : nodes)
104  {
105  memoryx::GraphNodePtr node = memoryx::GraphNodePtr::dynamicCast(basenode);
106 
107  auto size = node->getOutdegree();
108  for (int i = 0; i < size; ++i)
109  {
110  memoryx::GraphNodePtr nextNode = memoryx::GraphNodePtr::dynamicCast(node->getAdjacentNode(i)->getEntity());
111 
112  Eigen::Vector2f node1 = FramedPosePtr::dynamicCast(node->getPose())->toEigen().block<2, 1>(0, 3);
113  Eigen::Vector2f node2 = FramedPosePtr::dynamicCast(nextNode->getPose())->toEigen().block<2, 1>(0, 3);
114 
115  if ((node1 - node2).norm() > 1e-9)
116  {
117  Eigen::Vector2f result = VirtualRobot::MathTools::nearestPointOnSegment<Eigen::Vector2f>(node1, node2, robotPos);
118 
119  projections.push_back(EdgeProjection
120  {
121  .targetNode = nextNode,
122  .position = result
123  });
124  }
125  }
126  }
127 
128  return projections;
129 }
130 
131 
133 {
134  ARMARX_VERBOSE << "CalcPath::onEnter()";
135  PlatformContext* context = getContext<PlatformContext>();
136 
137  auto graphSegment = context->priorKnowledgePrx->getGraphSegment();
138  viz::ScopedClient arviz(viz::Client::createFromTopic("MovePlatformToLandmark/CalcPath", context->arvizTopic));
139 
140  std::vector<armarx::Vector3Ptr> targetPositions;
141 
142  // Does the scene exist
143  const std::string sceneName = in.getSceneName();
144  if (!graphSegment->hasScene(sceneName))
145  {
146  ARMARX_WARNING << "Target scene '" << sceneName << "' does not exist in menory";
147  out.settargetPositions(targetPositions);
148  emitEvNoPathFound();
149  return;
150  }
151 
152  // Does the target landmark exist
153  const std::string landmark = in.gettargetLandmark();
154  if (!graphSegment->hasNodeWithName(sceneName, landmark))
155  {
156  ARMARX_WARNING << "Target landmark '" << landmark << "' doesn't exist in graph (scene) '" << sceneName << "'";
157  auto nodes = graphSegment->getNodesByScene(sceneName);
158  for (auto& node : nodes)
159  {
160  ARMARX_INFO << "node: " << node->getName();
161  }
162  out.settargetPositions(targetPositions);
163  sendEvent<EvNoPathFound>();
164  return;
165  }
166 
167  memoryx::GraphNodeBasePtr goalNode;
168  {
169  memoryx::GraphNodeBasePtr landmarkNode = graphSegment->getNodeFromSceneByName(sceneName, landmark);
170  ARMARX_CHECK_NOT_NULL(landmarkNode) << "Could not find node with name '" << landmark << "' in scene '" << sceneName << "'";
171 
172  goalNode = context->graphNodePoseResolverPrx->getNearestRobotLocationNode(landmarkNode);
173  ARMARX_CHECK_NOT_NULL(goalNode) << "No nearest node found for landmark '" << landmark << "' in scene '" << sceneName << "'";
174  }
175  ARMARX_INFO << "Resolved target landmark to '" << goalNode->getName() << "'";
176 
177 
178  viz::Layer layerRobotPose = arviz.layer("Robot Pose");
179  viz::Layer layerClosestPoint = arviz.layer("Closest Point");
180 
181  // Get current position
182  ChannelRefPtr poseRef = context->getChannelRef(context->getPlatformUnitObserverName(), "platformPose");
183  const float platformPositionX = poseRef->getDataField("positionX")->getFloat();
184  const float platformPositionY = poseRef->getDataField("positionY")->getFloat();
185  const float platformYaw = poseRef->getDataField("rotation")->getFloat();
186 
187  Eigen::Vector3f currentPos(platformPositionX, platformPositionY, 0);
188  const Eigen::Vector2f currentPos2d = currentPos.head<2>();
189 
190  {
191  layerRobotPose.add(viz::Pose("RobotPose").position(currentPos)
192  .orientation(VirtualRobot::MathTools::rpy2eigen3f(0, 0, platformYaw)));
193  }
194 
195  std::vector<EdgeProjection> projections = getNearestPositionOnEdges(graphSegment->getNodesByScene(sceneName), currentPos2d);
196  if (projections.empty())
197  {
198  ARMARX_ERROR << "Could not find nearest point on graph";
199  emitEvNoPathFound();
200  return;
201  }
202 
203  std::sort(projections.begin(), projections.end(), [&currentPos2d](const auto & p1, const auto & p2)
204  {
205  const float c1 = (p1.position - currentPos2d).norm();
206  const float c2 = (p2.position - currentPos2d).norm();
207 
208  return c1 < c2;
209  });
210 
211  // Projections are sorted by distance to current position.
212  std::optional<EdgeProjection> bestProjection;
213  ::memoryx::GraphNodeBaseList bestPath;
214  float bestPathCosts = std::numeric_limits<float>::max();
215 
216  for (const EdgeProjection& projection : projections)
217  {
218  const Eigen::Vector3f nodePosition = fromIce(projection.targetNode->getPose()->position);
219  const float distToNode = (nodePosition - currentPos).norm();
220  ARMARX_INFO << "Current node: '" << projection.targetNode->getName() << "' | " << VAROUT(distToNode);
221 
222  // Find a path from the closest node to the target
223  ::memoryx::GraphNodeBaseList path = graphSegment->aStar(projection.targetNode->getId(), goalNode->getId());
224  // ToDo: Cost = (current pos -> proj.position) + (proj.position -> proj.targetNode)
225  float pathCost = distToNode + getPathLength(path);
226 
227  if (path.empty())
228  {
229  continue;
230  }
231 
232  // Projections can have two entries with the same length right after another (undirected edge)
233  // We only stop after we visited both directions.
234  if (bestProjection.has_value() and (bestProjection->position - projection.position).norm() > 1e-4)
235  {
236  break;
237  }
238 
239  if (pathCost < bestPathCosts)
240  {
241  bestProjection = projection;
242  bestPath = path;
243  bestPathCosts = pathCost;
244  }
245  }
246 
247  if (not bestProjection.has_value())
248  {
249  ARMARX_WARNING << "No path found";
250  out.settargetPositions(targetPositions);
251  emitEvNoPathFound();
252  return;
253  }
254 
255  const Eigen::Vector2f nearestPoint = bestProjection->position;
256  ARMARX_INFO << "Nearest Point on graph: " << nearestPoint.transpose();
257  {
258  Eigen::Vector3f closestPointPos;
259  closestPointPos << nearestPoint, 0;
260 
261  layerClosestPoint.add(viz::Sphere("Closest Point").position(closestPointPos).radius(100).color(simox::Color::green()));
262  layerClosestPoint.add(viz::Cylinder("To Closest Point").fromTo(currentPos, closestPointPos)
263  .radius(30).color(simox::Color::green(96)));
264  }
265 
266  // arviz.commit({layerRobotPose, layerClosestPoint});
267 
268  bool fixedOrentation = true;
269  float length = getPathLength(bestPath);
270 
271  bool useWaypointOrientations = in.getUseWaypointOrientations();
272  if (!useWaypointOrientations && length > in.getdriveMode_lookAhead_thresholdMM())
273  {
274  ARMARX_INFO << "long path (" << length << " mm) -> rotating platform towards moving direction";
275  fixedOrentation = false;
276  }
277 
278  Eigen::Vector3f rpy;
279  PosePtr pose = PosePtr::dynamicCast(bestPath.back()->getPose());
280  VirtualRobot::MathTools::eigen4f2rpy(pose->toEigen(), rpy);
281  const float goalYaw = rpy[2];
282  ::armarx::FramedPosePtr lastPose;
283  float lastAlpha = 0;
284  int count = 0;
285 
286  for (auto& node : bestPath)
287  {
288  ::armarx::FramedPosePtr currentPose = FramedPosePtr::dynamicCast(node->getPose());
289  Vector3Ptr v = new Vector3();
290  v->x = currentPose->position->x;
291  v->y = currentPose->position->y;
292 
293  if (useWaypointOrientations)
294  {
295  VirtualRobot::MathTools::eigen4f2rpy(currentPose->toEigen(), rpy);
296  v->z = rpy[2];
297  ARMARX_INFO << "Using waypoint orientation: " << v->z;
298  }
299  else if (fixedOrentation)
300  {
301  v->z = goalYaw;
302  }
303  else
304  {
305  if (count <= 0 || count >= int(bestPath.size() - 1))
306  {
307  // first /last pos
308  VirtualRobot::MathTools::eigen4f2rpy(currentPose->toEigen(), rpy);
309  ARMARX_DEBUG << "start or last pose of path, using orientation of waypoint: " << rpy[2];
310  v->z = rpy[2];
311  lastAlpha = rpy[2];
312  }
313  else
314  {
315  double x = currentPose->position->x - lastPose->position->x;
316  double y = currentPose->position->y - lastPose->position->y;
317  double dist = std::sqrt(x * x + y * y);
318 
319  if (dist < 500)
320  {
321  ARMARX_DEBUG << "points close together, using last orientation: " << lastAlpha;
322  v->z = lastAlpha;
323  }
324  else
325  {
326  // compute alpha
327  Eigen::Vector2d a(x, y);
328  a.normalize();
329  Eigen::Vector2d b(0, 1); // vector in y dir == 0 degrees
330  v->z = - (std::atan2(b.y(), b.x()) - std::atan2(a.y(), a.x()));
331 
332  if (v->z < 0)
333  {
334  v->z += 2.0 * M_PI;
335  }
336 
337  //v->z = acos(a.dot(b));
338  lastAlpha = v->z;
339  ARMARX_DEBUG << "waypoint angle between " << a.transpose() << " and " << b.transpose() << ": " << v->z;
340  }
341 
342  }
343 
344  lastPose = currentPose;
345  count++;
346  }
347 
348  targetPositions.push_back(v);
349  ARMARX_INFO << "waypoint #" << targetPositions.size() << ": " << node->getName() << " Coordinates:\n " << v->output();
350  }
351 
352  // Replace initial node with closest point on edge
353  Vector3Ptr v(new Vector3(nearestPoint.x(), nearestPoint.y(), Vector3Ptr::dynamicCast(targetPositions[0])->toEigen().z()));
354  targetPositions.insert(targetPositions.begin(), v);
355 
356  out.settargetPositions(targetPositions);
357  emitEvPathFound();
358 }
359 
361 {
362  PlatformContext* context = getContext<PlatformContext>();
363  context->debugDrawer->removeSphereDebugLayerVisu("closestPoint");
364 }
365 
366 float CalcPath::getPathLength(::memoryx::GraphNodeBaseList& path)
367 {
368  float l = 0.0f;
369  ::armarx::FramedPoseBasePtr lastPose;
370 
371  for (auto& node : path)
372  {
373  if (!lastPose)
374  {
375  lastPose = node->getPose();
376  continue;
377  }
378 
379  ::armarx::FramedPoseBasePtr currentPose = node->getPose();
380  float x = currentPose->position->x - lastPose->position->x;
381  float y = currentPose->position->y - lastPose->position->y;
382  l += std::sqrt(x * x + y * y);
383  lastPose = currentPose;
384  }
385 
386  return l;
387 }
388 
389 // DO NOT EDIT NEXT FUNCTION
390 std::string CalcPath::GetName()
391 {
392  return "CalcPath";
393 }
394 
395 // DO NOT EDIT NEXT FUNCTION
397 {
398  return XMLStateFactoryBasePtr(new CalcPath(stateData));
399 }
400 
armarx::PlatformContext::getPlatformUnitObserverName
std::string getPlatformUnitObserverName()
Definition: PlatformContext.h:115
GfxTL::sqrt
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition: VectorXD.h:662
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:180
getNearestPositionOnEdge
bool getNearestPositionOnEdge(const ::memoryx::GraphNodeBaseList &nodes, float currentX, float currentY, Eigen::Vector2f &closest, memoryx::GraphNodePtr &edgeNode1, memoryx::GraphNodePtr &edgeNode2)
Definition: CalcPath.cpp:53
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:183
armarx::viz::Client::createFromTopic
static Client createFromTopic(std::string const &componentName, armarx::viz::Topic::ProxyType const &topic)
Definition: Client.cpp:36
armarx::PlatformGroup::CalcPath::CalcPath
CalcPath(XMLStateConstructorParams stateData)
Definition: CalcPath.cpp:46
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
armarx::PlatformGroup::CalcPath::onExit
void onExit() override
Definition: CalcPath.cpp:360
armarx::PlatformContext::graphNodePoseResolverPrx
memoryx::GraphNodePoseResolverInterfacePrx graphNodePoseResolverPrx
Definition: PlatformContext.h:123
ScopedClient.h
armarx::XMLStateConstructorParams
Definition: XMLState.h:50
armarx::viz::ScopedClient
viz::Client that will delete (clear) committed layers when destroyed.
Definition: ScopedClient.h:42
armarx::PlatformGroup::CalcPath::GetName
static std::string GetName()
Definition: CalcPath.cpp:390
armarx::viz::Layer::add
void add(ElementT const &element)
Definition: Layer.h:29
armarx::StatechartContext::getChannelRef
ChannelRefPtr getChannelRef(const std::string &observerName, const std::string &channelName) override
Definition: StatechartContext.cpp:142
EdgeProjection::position
Eigen::Vector2f position
Definition: CalcPath.cpp:96
EdgeProjection
Projection of point on an edge of the graph.
Definition: CalcPath.cpp:93
armarx::viz::Sphere
Definition: Elements.h:134
armarx::viz::ElementOps::position
DerivedT & position(float x, float y, float z)
Definition: ElementOps.h:127
IceInternal::Handle< GraphNode >
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
armarx::XMLStateTemplate
Class for legacy to stay compatible with old statecharts.
Definition: XMLState.h:137
M_PI
#define M_PI
Definition: MathTools.h:17
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
armarx::viz::Cylinder
Definition: Elements.h:74
armarx::viz::ElementOps::orientation
DerivedT & orientation(Eigen::Quaternionf const &ori)
Definition: ElementOps.h:140
GraphNode.h
MemoryXCoreObjectFactories.h
armarx::viz::Pose
Definition: Elements.h:179
max
T max(T t1, T t2)
Definition: gdiam.h:48
armarx::PlatformGroup::CalcPath::Registry
static SubClassRegistry Registry
Definition: CalcPath.h:51
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:189
armarx::fromIce
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
Definition: ice_conversions_boost_templates.h:26
armarx::PlatformGroup::CalcPath
Definition: CalcPath.h:36
armarx::XMLStateFactoryBasePtr
IceInternal::Handle< XMLStateFactoryBase > XMLStateFactoryBasePtr
Definition: XMLState.h:65
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
EdgeProjection::targetNode
memoryx::GraphNodePtr targetNode
Definition: CalcPath.cpp:95
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:182
armarx::PlatformContext::arvizTopic
armarx::viz::TopicPrx arvizTopic
Definition: PlatformContext.h:127
armarx::PlatformGroup::CalcPath::getPathLength
float getPathLength(::memoryx::GraphNodeBaseList &path)
Definition: CalcPath.cpp:366
memoryx::KBM::Vector3
Eigen::Vector3d Vector3
Definition: kbm.h:41
MemoryXTypesObjectFactories.h
armarx::PlatformContext::priorKnowledgePrx
memoryx::PriorKnowledgeInterfacePrx priorKnowledgePrx
Definition: PlatformContext.h:131
armarx::PlatformContext
Definition: PlatformContext.h:64
armarx::viz::ScopedClient::layer
Layer layer(std::string const &name) const
Definition: ScopedClient.cpp:34
armarx::PlatformGroup::CalcPath::CreateInstance
static XMLStateFactoryBasePtr CreateInstance(XMLStateConstructorParams stateData)
Definition: CalcPath.cpp:396
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::viz::Layer
Definition: Layer.h:12
CalcPath.h
armarx::PlatformGroup::CalcPath::onEnter
void onEnter() override
Definition: CalcPath.cpp:132
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
getNearestPositionOnEdges
std::vector< EdgeProjection > getNearestPositionOnEdges(const ::memoryx::GraphNodeBaseList &nodes, Eigen::Vector2f robotPos)
Definition: CalcPath.cpp:99
armarx::PlatformContext::debugDrawer
DebugDrawerInterfacePrx debugDrawer
Definition: PlatformContext.h:122
armarx::green
QColor green()
Definition: StyleSheets.h:72
ChannelRef.h
norm
double norm(const Point &a)
Definition: point.hpp:94