RobotIK.h
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2015-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 RobotComponents::ArmarXObjects::RobotIK
19  * @author Joshua Haustein ( joshua dot haustein at gmail dot com )
20  * @date 2015
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #pragma once
26 
27 #include <mutex>
28 
29 #include <VirtualRobot/IK/GenericIKSolver.h>
30 
34 
35 #include <RobotAPI/interface/core/RobotState.h>
36 #include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
38 
39 #include <RobotComponents/interface/components/RobotIK.h>
40 
41 namespace armarx
42 {
43  /**
44  * \class RobotIKPropertyDefinition
45  * \brief
46  */
48  {
49  public:
51  {
52  defineRequiredProperty<std::string>(
53  "RobotFileName", "Filename of VirtualRobot robot model (e.g. robot_model.xml)");
54  //Define optional properties
55  defineOptionalProperty<std::string>(
56  "RobotStateComponentName",
57  "RobotStateComponent",
58  "Name of the robot state component that should be used");
59  defineOptionalProperty<std::string>("ReachabilitySpacesFolder",
60  "Path to a folder containing reachability spaces");
61  defineOptionalProperty<int>(
62  "NumIKTrials", 10, "Number of trials to find an ik solution");
63  defineOptionalProperty<std::string>(
64  "InitialReachabilitySpaces",
65  "",
66  "Reachability spaces to load initially (semi-colon separated)");
67  }
68  };
69 
70  /**
71  * \defgroup Component-RobotIK RobotIK
72  * \ingroup RobotComponents-Components
73  * \brief Provides IK solving methods from VirtualRobot (see [Simox](http://simox.sourceforge.net/)).
74  *
75  * RobotIK provides a set of functions that allow computing IKs for any kinematic chain
76  * in a robot. This component requires the following properties:
77  * - RobotFileName: The VirtualRobot robot model to be used.
78  * - RobotStateComponentName: The name of a robot state component.
79  *
80  * \image html Armar3_IK_small.png "An exemplary IK task and its solution."
81  *
82  * Furthermore, there are the following optional properties:
83  * - ReachabilitySpacesFolder: A Path to a folder containing reachability spaces.
84  * - NumIKTrials: The number of trials the underlying ik solver tries to find a solution before giving up (default: 10).
85  *
86  * The robot model is required to solve the IK. Some of the provided functionalities require the current robot state,
87  * which is retrieved from the robot state component specified in the properties. These functions will only work properly,
88  * if the robot model used by the robot state component is identical to the robot model of this component.
89  *
90  * The functionalities include:
91  * - computation of an IK solution for a kinematic chain given a goal TCP pose.
92  * - computation of an IK solution for a set of robot joints such that
93  * the projection of the center of mass to the support surface lies within a goal region.
94  * - computation of a joint value gradient to minimize the workspace error for several tasks simultaneously.
95  * - creation and query of reachability spaces for kinematic chains.
96  *
97  * A reachability space for a kinematic chain allows a fast check whether
98  * a TCP pose is reachable. Creating a reachability space, however, is a computational intensive process
99  * that should be done offline. You may create a reachability space by calling the respective function
100  * or by specifying a path to a folder, ReachabilitySpacesFolder, that contains a set of reachability spaces.
101  * If ReachabilitySpacesFolder is specified, each file in the folder is attempted to be loaded as reachability space
102  * during initialization.
103  *
104  * While this implementation allows parallel access to its interface functions,
105  * it is not optimized towards maximizing parallelism.
106  * If you need to access this component from a large number of threads/processes
107  * and you care about performance, you should consider creating multiple instances
108  * of this component or using local instances of the IK solver from Simox instead.
109  *
110  * Furthermore, at the beginning of an operation this component synchronizes its
111  * internal robot state with that provided by the robot state component.
112  * This can lead to invalid IK solutions if the robot state changes while computation is still in progress.
113  * For example, imagine you compute an IK solution just
114  * for the forearm and the wrist given a global eef pose. If during the computation the configuration
115  * of the elbow changes, the computed ik solution will no longer achieve the desired eef pose.
116  *
117  * Also see [Simox-Tutorial] (http://sourceforge.net/p/simox/wiki/VirtualRobot/) for more information
118  * of how to use Simox for IK solving.
119  */
120 
121  /**
122  * @ingroup Component-RobotIK
123  * @brief Refer to \ref Component-RobotIK
124  */
126  virtual public Component,
127  virtual public RobotIKInterface
128  {
129  public:
130  /**
131  * \return the robot xml filename as specified in the configuration
132  */
133  virtual std::string getRobotFilename(const Ice::Current&) const;
134 
135  /**
136  * Create an instance of RobotIKPropertyDefinitions.
137  */
138  PropertyDefinitionsPtr createPropertyDefinitions() override;
139 
140  std::string
141  getDefaultName() const override
142  {
143  return "RobotIK";
144  }
145 
146  /**
147  * @brief Computes a single IK solution for the given robot node set and desired TCP pose.
148  * @details The TCP pose can be defined in any frame and is converted internally to a global pose
149  * according to the current robot state. The CartesianSelection
150  * parameter defines which part of the target pose should be reached.
151  *
152  * @param robotNodeSetName The name of a robot node set (robot node set) that is either stored
153  * within the robot model or has been defined via \ref defineRobotNodeSet.
154  * @param tcpPose The framed target pose for the TCP.
155  * @param cs Specifies which part of the pose needs to be reached by the IK, e.g. the position only,
156  * the orientation only or all.
157  * @return A map that maps each joint name to its value in the found IK solution.
158  */
159  NameValueMap computeIKFramedPose(const std::string& robotNodeSetName,
160  const FramedPoseBasePtr& tcpPose,
162  const Ice::Current& = Ice::emptyCurrent) override;
163 
164  /**
165  * @brief Computes a single IK solution for the given robot node set and desired global TCP pose.
166  * @details The TCP pose is assumed to be in the global frame. The CartesianSelection
167  * parameter defines which part of the target pose should be reached.
168  *
169  * @param robotNodeSetName The name of a robot node set (robot node set) that is either stored
170  * within the robot model or has been defined via \ref defineRobotNodeSet.
171  * @param tcpPose The global target pose for the TCP.
172  * @param cs Specifies which part of the pose needs to be reached by the IK, e.g. the position only,
173  * the orientation only or all.
174  * @return A map that maps each joint name to its value in the found IK solution.
175  */
176  NameValueMap computeIKGlobalPose(const std::string& robotNodeSetName,
177  const PoseBasePtr& tcpPose,
179  const Ice::Current& = Ice::emptyCurrent) override;
180 
181  /**
182  * @brief Computes a single IK solution, error and reachability for the given robot node set and desired global TCP pose.
183  * @details The TCP pose is assumed to be in the global frame. The CartesianSelection
184  * parameter defines which part of the target pose should be reached.
185  *
186  * @param robotNodeSetName The name of a robot node set (robot node set) that is either stored
187  * within the robot model or has been defined via \ref defineRobotNodeSet.
188  * @param tcpPose The global target pose for the TCP.
189  * @param cs Specifies which part of the pose needs to be reached by the IK, e.g. the position only,
190  * the orientation only or all.
191  * @return A map that maps each joint name to its value in the found IK solution, the reachability and computational error.
192  */
193  ExtendedIKResult
194  computeExtendedIKGlobalPose(const std::string& robotNodeSetName,
195  const PoseBasePtr& tcpPose,
197  const Ice::Current& = Ice::emptyCurrent) override;
198 
199  /**
200  * @brief Computes an IK solution for the given robot joints such that the center of mass lies above the
201  * given point.
202  * @details
203  *
204  * @param robotNodeSetJoints Name of the robot node set that contains the joints you wish to compute the IK for.
205  * @param comIK A center of mass description. Note that the priority field is relevant for this function as there
206  * is only a single CoM of descriptor.
207  *
208  * @return The ik-solution. Returns an empty vector if there is no solution.
209  */
210  NameValueMap computeCoMIK(const std::string& robotNodeSetJoints,
211  const CoMIKDescriptor& desc,
212  const Ice::Current& = Ice::emptyCurrent) override;
213 
214  /**
215  * @brief Computes a configuration gradient in order to solve several tasks/constraints simultaneously.
216  * @details This function allows you to use the HierarchicalIK solver provided by Simox.
217  * It computes a configuration gradient for the given robot node set that minimizes the workspace errors
218  * for multiple tasks simultaneously. You can specify IK tasks, a center of mass task and a joint limit avoidance task.
219  * For details for the different type of tasks, see the parameter description. You must define a priority for each task.
220  * The task with maximal priority is the first task to be solved. Each subsequent task is then solved
221  * within the null space of the previous task. <b> Note that this function returns a gradient and NOT
222  * an absolute IK solution. The gradient is computed on the current configuration of the robot. <\b>.
223  * The gradient is computed from the current robot configuration.
224  *
225  * See @url http://simox.sourceforge.net/documentation/class_virtual_robot_1_1_hierarchical_i_k.html
226  * and @url http://sourceforge.net/p/simox/wiki/VirtualRobot/#hierarchical-ik-solving for more information.
227  *
228  * @param robotNodeSet The robot node set (e.g. kinematic tree) you wish to compute the gradient for.
229  * @param diffIKs A list of IK tasks. Each IK task specifies a TCP and a desired pose for this TCP.
230  * @param comIK A center of mass tasks. Defines where the center should be and its priority. Is only used if the
231  CoM-task is enabled.
232  * @param stepSize
233  * @param avoidJointLimits Set whether or not to avoid joint limits.
234  * @param enableCenterOfMass Set whether or not to adjust the center of mass.
235  * @return A configuration gradient...
236  */
237  NameValueMap computeHierarchicalDeltaIK(const std::string& robotNodeSet,
238  const IKTasks& iktasks,
239  const CoMIKDescriptor& comIK,
240  float stepSize,
241  bool avoidJointLimits,
242  bool enableCenterOfMass,
243  const Ice::Current& = Ice::emptyCurrent) override;
244 
245  /**
246  * @brief Creates a new reachability space for the given robot node set.
247  * @details If there is no reachability space for the given robot node set yet, a new one is created. This may take
248  * some time. The function returns true iff a reachability space for the given robot node set exists after
249  * execution of this function.
250  *
251  * @param chainName The name of a defined robot node set. This can be either a robot node set that is defined in the
252  * robot model or a robot node set that has been manually defined calling \ref defineRobotNodeSet.
253  * @param coordinateSystem The name of the robot node in whose coordinate system the reachability space shall be defined
254  * in. If you wish to choose the global coordinate system, pass an empty string.
255  * Note, however, that any reachability space defined in the
256  * global coordinate system gets invalidated once the robot moves.
257  * @param stepTranslation The extend of a voxel dimension in translational dimensions (x,y,z) [mm]
258  * @param stepRotation The extend of a voxel dimension in rotational dimensions (roll,pitch,yaw) [rad]
259  * @param minBounds The minimum workspace poses (x,y,z,ro,pi,ya) given in the base node's coordinate system [mm and rad]
260  * @param maxBounds The maximum workspace poses (x,y,z,ro,pi,ya) given in base node's coordinate system [mm and rad]
261  * @param numSamples The number of tcp samples to take to create the reachability space (e.g 1000000)
262  * @return True iff the a reachability space for the given robot node set is available after execution of this function.
263  * False in case of a failure, e.g. there is no chain with the given name.
264  */
265  bool createReachabilitySpace(const std::string& chainName,
266  const std::string& coordinateSystem,
267  float stepTranslation,
268  float stepRotation,
269  const WorkspaceBounds& minBounds,
270  const WorkspaceBounds& maxBounds,
271  int numSamples,
272  const Ice::Current& = Ice::emptyCurrent) override;
273 
274  /**
275  * @brief Defines a new robot node set.
276  * @details Define a new robot node set with the given name that consists out of the given list of nodes with given
277  * TCP and root frame. Iff the chain is successfully added or already exists, <it>true</it> is returned.
278  * @param name The name of the robot node set.
279  * @param nodes The list of robot nodes that make up the robot node set.
280  * @param tcpName The name of the TCP node.
281  * @param rootNode The name of the kinematic root.
282  *
283  * @return True, iff chain was added or already exists. False, iff a different chain with similar name already exists.
284  */
285  bool defineRobotNodeSet(const std::string& name,
286  const NodeNameList& nodes,
287  const std::string& tcpName,
288  const std::string& rootNode,
289  const Ice::Current& = Ice::emptyCurrent) override;
290 
291  /**
292  * @brief Returns whether this component has a reachability space for the given robot node set.
293  * @details True if there is a reachability space available, else false.
294  *
295  * @param chainName Name of the robot node set.
296  * @return True if there is a reachability space available, else false.
297  */
298  bool hasReachabilitySpace(const std::string& chainName,
299  const Ice::Current& = Ice::emptyCurrent) const override;
300 
301  /**
302  * @brief Returns whether a given framed pose is currently reachable by the TCP of the given robot node set.
303  * @details To determine whether a pose is reachable a reachability space for the given robot node set is
304  * required. If no such space exists, the function returns <it>false<\it>.
305  * Call \ref createReachabilitySpace first to ensure there is such a space.
306  *
307  * @param chainName A name of a robot node set either defined in the robot model or previously defined via
308  * \ref defineRobotNodeSet.
309  * @param framedPose A framed pose to check for reachability. The pose is transformed into a global pose using the
310  * current robot state.
311  *
312  * @return True, if the pose is reachable by the TCP of the given chain. False, if it is not reachable or
313  * there is no reachability space for the given chain available.
314  */
315  bool isFramedPoseReachable(const std::string& chainName,
316  const FramedPoseBasePtr& tcpPose,
317  const Ice::Current& = Ice::emptyCurrent) const override;
318 
319  /**
320  * @brief Returns whether a given global pose is currently reachable by the TCP of the given robot node set.
321  * @details To determine whether a pose is reachable a reachability space for the given robot node set is
322  * required. If no such space exists, the function returns <it>false<\it>.
323  * Call \ref createReachabilitySpace first to ensure there is such a space.
324  *
325  * @param chainName A name of a robot node set either defined in the robot model or previously defined via
326  * \ref defineRobotNodeSet.
327  * @param pose A global pose to check for reachability.
328  *
329  * @return True, if the pose is reachable by the TCP of the given chain. False, if it is not reachable or
330  * there is no reachability space for the given chain available.
331  */
332  bool isPoseReachable(const std::string& chainName,
333  const PoseBasePtr& tcpPose,
334  const Ice::Current& = Ice::emptyCurrent) const override;
335 
336  /**
337  * @brief Loads the reachability space from the given file.
338  * @details If loading the reachability space succeeds, the reachability space is ready to be used after this function
339  * terminates. A reachability space can only be loaded if there is no reachability space for the respective
340  * robot node set yet.
341  *
342  * @param filename Binary file containing a reachability space. Ensure that the path is valid and accessible from
343  * where this component is running.
344  * @return True iff loading the reachability space was successful.
345  */
346  bool loadReachabilitySpace(const std::string& filename,
347  const Ice::Current& = Ice::emptyCurrent) override;
348 
349  /**
350  * @brief Saves a previously created reachability space of the given robot node set.
351  * @details A reachability space for a robot node set can only be saved, if actually is one.
352  * You can check whether a reachability space is available by calling \ref hasReachabilitySpace(robotNodeSet).
353  *
354  * @param robotNodeSet The robot node set for which you wish to save the reachability space.
355  * @param filename The filename if the file(must be an accessible path for this component) you wish to save the space in.
356  * @return True iff saving was successful.
357  */
358  bool saveReachabilitySpace(const std::string& robotNodeSet,
359  const std::string& filename,
360  const Ice::Current& = Ice::emptyCurrent) const override;
361 
362 
363  protected:
364  /**
365  * Load and create a VirtualRobot::Robot instance from the RobotFileName
366  * property.
367  */
368  void onInitComponent() override;
369  void onConnectComponent() override;
370  void onDisconnectComponent() override;
371 
372  private:
373  bool solveIK(const Eigen::Matrix4f& tcpPose,
375  VirtualRobot::RobotNodeSetPtr nodeSet);
376  void computeIK(const std::string& robotNodeSetName,
377  const Eigen::Matrix4f& tcpPose,
379  NameValueMap& iksolution);
380 
381  void computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
382  const Eigen::Matrix4f& tcpPose,
384  NameValueMap& iksolution);
385 
386  void computeIK(const std::string& robotNodeSetName,
387  const Eigen::Matrix4f& tcpPose,
389  ExtendedIKResult& iksolution);
390 
391  void computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
392  const Eigen::Matrix4f& tcpPose,
394  ExtendedIKResult& iksolution);
395 
396  Eigen::Matrix4f toGlobalPose(const FramedPoseBasePtr& tcpPose) const;
397  Eigen::Matrix4f toReachabilityMapFrame(const FramedPoseBasePtr& tcpPose,
398  const std::string& chainName) const;
399 
400  bool isReachable(const std::string& setName, const Eigen::Matrix4f& tcpPose) const;
401 
403  convertCartesianSelection(armarx::CartesianSelection cs) const;
404 
405  VirtualRobot::JacobiProvider::InverseJacobiMethod
406  convertInverseJacobiMethod(armarx::InverseJacobiMethod aenum) const;
407 
408  void synchRobot() const;
409 
410  // Lock this mutex if you plan to modify the robot model
411  // Exception: When adding node sets we don't need to.
412  // Invariant: We never delete node sets nor nodes!
413  mutable std::recursive_mutex _modifyRobotModelMutex;
414  // Lock this mutex if you are adding a node set, to ensure we do not add
415  // a similar node set at the same time.
416  mutable std::recursive_mutex _editRobotNodeSetsMutex;
417  // Lock this mutex if you are reading or editing the reachability cache.
418  mutable std::recursive_mutex _accessReachabilityCacheMutex;
419  // Needs to be locked when computing IKs! Internally thread safe though.
420  VirtualRobot::RobotPtr _robotModel;
421  std::string _robotFile;
422  RobotStateComponentInterfacePrx _robotStateComponentPrx;
423  SharedRobotInterfacePrx _synchronizedRobot;
424  DebugDrawerInterfacePrx debugDrawer;
425 
426  // Reachability cache: not thread safe, always lock!
427  using ReachabilityCacheType =
428  std::map<std::string, VirtualRobot::WorkspaceRepresentationPtr>;
429  ReachabilityCacheType _reachabilities;
430  int _numIKTrials;
431  };
432 
433 } // namespace armarx
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
Properties.h
armarx::PropertyDefinitionContainer::prefix
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
Definition: PropertyDefinitionContainer.h:345
RobotAPIObjectFactories.h
armarx::RobotIK
Refer to RobotIK.
Definition: RobotIK.h:125
ARMARXCOMPONENT_IMPORT_EXPORT
#define ARMARXCOMPONENT_IMPORT_EXPORT
Definition: ImportExportComponent.h:38
armarx::RobotIKPropertyDefinitions
Definition: RobotIK.h:47
armarx::NJointTaskSpaceDMPControllerMode::CartesianSelection
CartesianSelection
Definition: ControllerInterface.ice:34
filename
std::string filename
Definition: VisualizationRobot.cpp:86
Component.h
armarx::Component
Baseclass for all ArmarX ManagedIceObjects requiring properties.
Definition: Component.h:91
armarx::control::njoint_controller::platform::platform_follower_controller::NameValueMap
std::map< std::string, float > NameValueMap
Definition: PlatformFollowerController.h:88
armarx::RobotIKPropertyDefinitions::RobotIKPropertyDefinitions
RobotIKPropertyDefinitions(std::string prefix)
Definition: RobotIK.h:50
armarx::ComponentPropertyDefinitions
Default component property definition container.
Definition: Component.h:69
IceUtil::Handle< class PropertyDefinitionContainer >
IceInternal::ProxyHandle<::IceProxy::armarx::RobotStateComponentInterface >
armarx::RobotIK::getDefaultName
std::string getDefaultName() const override
Retrieve default name of component.
Definition: RobotIK.h:141
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
VirtualRobot::RobotPtr
std::shared_ptr< class Robot > RobotPtr
Definition: Bus.h:19
ImportExportComponent.h