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