HEBI C++ API  3.4.0
robot_model.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "hebi.h"
4 
5 #include <memory>
6 #include <vector>
7 
8 #include "Eigen/Eigen"
9 #include "util.hpp"
10 
11 using namespace Eigen;
12 
13 namespace hebi {
14 namespace robot_model {
15 
16 using Matrix4dVector = std::vector<Matrix4d, Eigen::aligned_allocator<Eigen::Matrix4d>>;
17 using MatrixXdVector = std::vector<MatrixXd, Eigen::aligned_allocator<Eigen::MatrixXd>>;
18 // The result of an IK operation. More fields will be added to this structure
19 // in future API releases.
20 struct IKResult {
21  HebiStatusCode result; // Success or failure
22 };
23 
24 class RobotModel;
25 
26 class Objective {
27  friend RobotModel;
28 
29 public:
30  virtual ~Objective() {}
31 
32 protected:
33  virtual HebiStatusCode addObjective(HebiIKPtr ik) const = 0;
34 };
35 
37 public:
38  EndEffectorPositionObjective(const Eigen::Vector3d&);
39  EndEffectorPositionObjective(double weight, const Eigen::Vector3d&);
40 
41 private:
42  HebiStatusCode addObjective(HebiIKPtr ik) const override;
43  double _weight, _x, _y, _z;
44 };
45 
46 class EndEffectorSO3Objective final : public Objective {
47 public:
48  EndEffectorSO3Objective(const Eigen::Matrix3d&);
49  EndEffectorSO3Objective(double weight, const Eigen::Matrix3d&);
50 
51 private:
52  HebiStatusCode addObjective(HebiIKPtr ik) const override;
53  double _weight;
54  const double _matrix[9];
55 };
56 
57 class EndEffectorTipAxisObjective final : public Objective {
58 public:
59  EndEffectorTipAxisObjective(const Eigen::Vector3d&);
60  EndEffectorTipAxisObjective(double weight, const Eigen::Vector3d&);
61 
62 private:
63  HebiStatusCode addObjective(HebiIKPtr ik) const override;
64  double _weight, _x, _y, _z;
65 };
66 
67 class JointLimitConstraint final : public Objective {
68 public:
69  JointLimitConstraint(const Eigen::VectorXd& min_positions, const Eigen::VectorXd& max_positions);
70  JointLimitConstraint(double weight, const Eigen::VectorXd& min_positions, const Eigen::VectorXd& max_positions);
71 
72 private:
73  HebiStatusCode addObjective(HebiIKPtr ik) const override;
74  double _weight;
75  Eigen::VectorXd _min_positions;
76  Eigen::VectorXd _max_positions;
77 
78 public:
79  // Allow Eigen member variables:
80  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
81 };
82 
91 template<size_t T>
92 inline void custom_objective_callback_wrapper(void* user_data, size_t num_positions, const double* positions,
93  double* errors);
94 
134 template<size_t N>
135 class CustomObjective final : public Objective {
136 public:
137  // This function is called with the following parameters:
138  // const std::vector<double>& positions
139  // std::array<double, N>& errors (NOTE: FILL THIS IN VIA THE CALLBACK FUNCTION)
140  using ObjectiveCallback = std::function<void(const std::vector<double>&, std::array<double, N>&)>;
141 
142  CustomObjective(ObjectiveCallback error_function) : _weight(1.0f), _callback(error_function) {}
143  CustomObjective(double weight, ObjectiveCallback error_function) : _weight(weight), _callback(error_function) {}
144 
145  // Note -- internal function to be called only from
146  // custom_objective_callback_wrapper.
147  void callCallback(void*, size_t num_positions, const double* positions, double* errors) const {
148  // Note -- the data here is copied to/from the C-style arrays. This isn't
149  // optimally efficient, but allows us to use type-checked C++ vectors and
150  // arrays. For performance critical applications, this could be modified
151  // to support user callbacks using the raw C-style arrays directly.
152 
153  // Process data into C++ structures.
154  std::vector<double> positions_array(num_positions);
155  for (size_t i = 0; i < num_positions; ++i)
156  positions_array[i] = positions[i];
157  // Note -- std::array is not guaranteed to be layout-compatible with a
158  // C-style array, even for POD, so we must copy here it we want the type
159  // safety of std::array.
160  std::array<double, N> errors_array;
161  for (size_t i = 0; i < N; ++i)
162  errors_array[i] = errors[i];
163 
164  _callback(positions_array, errors_array);
165 
166  for (size_t i = 0; i < N; ++i)
167  errors[i] = errors_array[i];
168  }
169 
170 private:
171  HebiStatusCode addObjective(HebiIKPtr ik) const override {
172  return hebiIKAddObjectiveCustom(ik, _weight, N, &custom_objective_callback_wrapper<N>,
173  const_cast<CustomObjective*>(this));
174  }
175  double _weight;
176  ObjectiveCallback _callback;
177 };
178 
184 template<size_t T>
185 inline void custom_objective_callback_wrapper(void* user_data, size_t num_positions, const double* positions,
186  double* errors) {
187  reinterpret_cast<CustomObjective<T>*>(user_data)->callCallback(user_data, num_positions, positions, errors);
188 }
189 
190 class ActuatorMetadata;
191 class BracketMetadata;
192 class JointMetadata;
193 class LinkMetadata;
194 class RigidBodyMetadata;
195 
196 enum class ElementType {
197  Other = HebiRobotModelElementTypeOther,
198  Actuator = HebiRobotModelElementTypeActuator,
199  Bracket = HebiRobotModelElementTypeBracket,
200  Joint = HebiRobotModelElementTypeJoint,
201  Link = HebiRobotModelElementTypeLink,
202  RigidBody = HebiRobotModelElementTypeRigidBody,
203  EndEffector = HebiRobotModelElementTypeEndEffector
204 };
205 
206 enum class FrameType {
207  CenterOfMass = HebiFrameTypeCenterOfMass,
208  Output = HebiFrameTypeOutput,
209  EndEffector = HebiFrameTypeEndEffector,
210  Input = HebiFrameTypeInput
211 };
212 
213 enum class JointType {
214  RotationX = HebiJointTypeRotationX,
215  RotationY = HebiJointTypeRotationY,
216  RotationZ = HebiJointTypeRotationZ,
217  TranslationX = HebiJointTypeTranslationX,
218  TranslationY = HebiJointTypeTranslationY,
219  TranslationZ = HebiJointTypeTranslationZ
220 };
221 
222 enum class ActuatorType {
223  X5_1 = HebiActuatorTypeX5_1,
224  X5_4 = HebiActuatorTypeX5_4,
225  X5_9 = HebiActuatorTypeX5_9,
226  X8_3 = HebiActuatorTypeX8_3,
227  X8_9 = HebiActuatorTypeX8_9,
228  X8_16 = HebiActuatorTypeX8_16,
229  R8_3 = HebiActuatorTypeR8_3,
230  R8_9 = HebiActuatorTypeR8_9,
231  R8_16 = HebiActuatorTypeR8_16
232 };
233 
234 enum class LinkType {
235  X5 = HebiLinkTypeX5,
236  X8 = HebiLinkTypeR8
237 };
238 
239 enum class LinkInputType {
240  RightAngle = HebiLinkInputTypeRightAngle,
241  Inline = HebiLinkInputTypeInline
242 };
243 
244 enum class LinkOutputType {
245  RightAngle = HebiLinkOutputTypeRightAngle,
246  Inline = HebiLinkOutputTypeInline
247 };
248 
249 enum class BracketType {
250  X5LightLeft = HebiBracketTypeX5LightLeft,
251  X5LightRight = HebiBracketTypeX5LightRight,
252  X5HeavyLeftInside = HebiBracketTypeX5HeavyLeftInside,
253  X5HeavyLeftOutside = HebiBracketTypeX5HeavyLeftOutside,
254  X5HeavyRightInside = HebiBracketTypeX5HeavyRightInside,
255  X5HeavyRightOutside = HebiBracketTypeX5HeavyRightOutside,
256  R8LightLeft = HebiBracketTypeR8LightLeft,
257  R8LightRight = HebiBracketTypeR8LightRight,
258  R8HeavyLeftInside = HebiBracketTypeR8HeavyLeftInside,
259  R8HeavyLeftOutside = HebiBracketTypeR8HeavyLeftOutside,
260  R8HeavyRightInside = HebiBracketTypeR8HeavyRightInside,
261  R8HeavyRightOutside = HebiBracketTypeR8HeavyRightOutside
262 };
263 
264 enum class EndEffectorType {
265  Custom = HebiEndEffectorTypeCustom,
266  X5Parallel = HebiEndEffectorTypeX5Parallel,
267  R8Parallel = HebiEndEffectorTypeR8Parallel
268 };
269 
270 
275  friend class RobotModel;
276 public:
277  MetadataBase() = default;
278  MetadataBase(const MetadataBase&) = delete;
279  MetadataBase& operator=(const MetadataBase&) = delete;
280  MetadataBase(MetadataBase&&) = default;
281  MetadataBase& operator=(MetadataBase&&) = default;
282 
284  return static_cast<ElementType>(metadata_.element_type_);
285  }
286 
292  const ActuatorMetadata* asActuator() const {
293  if (elementType() == ElementType::Actuator) {
294  return reinterpret_cast<const ActuatorMetadata*>(this);
295  }
296  return nullptr;
297  }
298 
304  const BracketMetadata* asBracket() const {
305  if (elementType() == ElementType::Bracket) {
306  return reinterpret_cast<const BracketMetadata*>(this);
307  }
308  return nullptr;
309  }
310 
316  const JointMetadata* asJoint() const {
317  if (elementType() == ElementType::Joint) {
318  return reinterpret_cast<const JointMetadata*>(this);
319  }
320  return nullptr;
321  }
322 
328  const LinkMetadata* asLink() const {
329  if (elementType() == ElementType::Link) {
330  return reinterpret_cast<const LinkMetadata*>(this);
331  }
332  return nullptr;
333  }
334 
341  if (elementType() == ElementType::RigidBody) {
342  return reinterpret_cast<const RigidBodyMetadata*>(this);
343  }
344  return nullptr;
345  }
346 
347 protected:
348  // Raw data can only be accessed by the sub classes
349  const HebiRobotModelElementMetadata& metadata() const { return metadata_; }
350 private:
351  HebiRobotModelElementMetadata metadata_;
352 };
353 
358 public:
362  ActuatorType actuatorType() const { return static_cast<ActuatorType>(metadata().actuator_type_); }
363 };
364 
369 public:
373  BracketType bracketType() const { return static_cast<BracketType>(metadata().bracket_type_); }
374 };
375 
379 class JointMetadata : public MetadataBase {
380 public:
384  JointType jointType() const { return static_cast<JointType>(metadata().joint_type_); }
385 };
386 
390 class LinkMetadata : public MetadataBase {
391 public:
395  LinkType linkType() const { return static_cast<LinkType>(metadata().link_type_); }
396 
400  float extension() const { return metadata().extension_; }
401 
405  float twist() const { return metadata().twist_; }
406 };
407 
411 class RigidBodyMetadata : public MetadataBase {};
412 
419 class RobotModel final {
420  friend Objective;
421 
422 private:
426  HebiRobotModelPtr const internal_;
427 
432  template<typename T>
433  HebiStatusCode addObjectives(HebiIKPtr ik, const T& objective) const {
434  static_assert(std::is_convertible<T*, Objective*>::value,
435  "Must pass arguments of base type hebi::robot_model::Objective to the variable args of solveIK!");
436  return static_cast<const Objective*>(&objective)->addObjective(ik);
437  }
438 
442  template<typename T, typename... Args>
443  HebiStatusCode addObjectives(HebiIKPtr ik, const T& objective, Args... args) const {
444  static_assert(std::is_convertible<T*, Objective*>::value,
445  "Must pass arguments of base type hebi::robot_model::Objective to the variable args of solveIK!");
446  auto res = static_cast<const Objective*>(&objective)->addObjective(ik);
447  if (res != HebiStatusSuccess)
448  return res;
449  return addObjectives(ik, args...);
450  }
451 
455  bool tryAdd(HebiRobotModelElementPtr element);
456 
461  RobotModel(HebiRobotModelPtr);
462 
463 public:
464 
465  using ActuatorType [[deprecated ("Replace with hebi::robot_model::ActuatorType")]] = robot_model::ActuatorType;
466  using BracketType [[deprecated ("Replace with hebi::robot_model::BracketType")]] = robot_model::BracketType;
467  using LinkType [[deprecated ("Replace with hebi::robot_model::LinkType")]] = robot_model::LinkType;
468 
473  RobotModel();
474 
478  static std::unique_ptr<RobotModel> loadHRDF(const std::string& file);
479 
484  static std::unique_ptr<RobotModel> loadHRDFString(const std::string& string);
485 
490  ~RobotModel() noexcept;
491 
503  void setBaseFrame(const Eigen::Matrix4d& base_frame);
504 
509  Eigen::Matrix4d getBaseFrame() const;
510 
520  size_t getFrameCount(FrameType frame_type) const;
521 
527  [[deprecated ("Replaced by hebi::robot_model::RobotModel::getFrameCount(hebi::robot_model::FrameType)")]]
528  size_t getFrameCount(HebiFrameType frame_type) const { return getFrameCount(static_cast<FrameType>(frame_type)); }
529 
534  size_t getDoFCount() const;
535 
549  bool addRigidBody(const Eigen::Matrix4d& com, const Eigen::VectorXd& inertia, double mass,
550  const Eigen::Matrix4d& output);
551 
561  bool addJoint(JointType joint_type);
562 
568  [[deprecated ("Replaced by hebi::robot_model::RobotModel::addJoint(hebi::robot_model::JointType)")]]
569  bool addJoint(HebiJointType joint_type) { return addJoint(static_cast<JointType>(joint_type)); }
570 
577  bool addActuator(robot_model::ActuatorType actuator_type);
578 
595  bool addLink(robot_model::LinkType link_type, double extension, double twist,
596  LinkInputType input_type = LinkInputType::RightAngle,
597  LinkOutputType output_type = LinkOutputType::RightAngle);
598 
605  bool addBracket(robot_model::BracketType bracket_type);
606 
615  bool addEndEffector(EndEffectorType end_effector_type);
624  bool addEndEffector(double x, double y, double z);
638  bool addEndEffector(const Eigen::Matrix4d& com, const Eigen::VectorXd& inertia, double mass,
639  const Eigen::Matrix4d& output);
645  void getForwardKinematics(FrameType, const Eigen::VectorXd& positions, Matrix4dVector& frames) const;
646 
652  [[deprecated ("Change first argument form HebiFrameType to hebi::robot_model::FrameType")]]
653  void getForwardKinematics(HebiFrameType frame_type, const Eigen::VectorXd& positions, Matrix4dVector& frames) const {
654  getForwardKinematics(static_cast<FrameType>(frame_type), positions, frames);
655  }
656 
682  void getFK(FrameType, const Eigen::VectorXd& positions, Matrix4dVector& frames) const;
683 
689  [[deprecated ("Change first argument form HebiFrameType to hebi::robot_model::FrameType")]]
690  void getFK(HebiFrameType frame_type, const Eigen::VectorXd& positions, Matrix4dVector& frames) const {
691  getFK(static_cast<FrameType>(frame_type), positions, frames);
692  }
693 
713  void getEndEffector(const Eigen::VectorXd& positions, Eigen::Matrix4d& transform) const;
714 
721  template<typename... Args>
722  IKResult solveInverseKinematics(const Eigen::VectorXd& initial_positions, Eigen::VectorXd& result,
723  Args... args) const {
724  return solveIK(initial_positions, result, args...);
725  }
726 
741  template<typename... Args>
742  IKResult solveIK(const Eigen::VectorXd& initial_positions, Eigen::VectorXd& result, Args... objectives) const {
743  // Create a HEBI C library IK object
744  auto ik = hebiIKCreate();
745 
746  // (Try) to add objectives to the IK object
747  IKResult res;
748  res.result = addObjectives(ik, objectives...);
749  if (res.result != HebiStatusSuccess) {
750  hebiIKRelease(ik);
751  return res;
752  }
753 
754  // Transfer/initialize from Eigen to C arrays
755  auto positions_array = new double[initial_positions.size()];
756  {
757  Map<Eigen::VectorXd> tmp(positions_array, initial_positions.size());
758  tmp = initial_positions;
759  }
760  auto result_array = new double[initial_positions.size()];
761 
762  // Call into C library to solve
763  res.result = hebiIKSolve(ik, internal_, positions_array, result_array, nullptr);
764 
765  // Transfer/cleanup from C arrays to Eigen
766  delete[] positions_array;
767  {
768  Map<Eigen::VectorXd> tmp(result_array, initial_positions.size());
769  result = tmp;
770  }
771  delete[] result_array;
772 
773  hebiIKRelease(ik);
774 
775  return res;
776  }
777 
783  void getJacobians(FrameType, const Eigen::VectorXd& positions, MatrixXdVector& jacobians) const;
784 
790  [[deprecated]]
791  void getJacobians(HebiFrameType frame_type, const Eigen::VectorXd& positions, MatrixXdVector& jacobians) const {
792  getJacobians(static_cast<FrameType>(frame_type), positions, jacobians);
793  }
794 
808  void getJ(FrameType, const Eigen::VectorXd& positions, MatrixXdVector& jacobians) const;
809 
815  [[deprecated ("Change first argument form HebiFrameType to hebi::robot_model::FrameType")]]
816  void getJ(HebiFrameType frame_type, const Eigen::VectorXd& positions, MatrixXdVector& jacobians) const {
817  getJ(static_cast<FrameType>(frame_type), positions, jacobians);
818  }
819 
825  void getJacobianEndEffector(const Eigen::VectorXd& positions, Eigen::MatrixXd& jacobian) const;
845  void getJEndEffector(const Eigen::VectorXd& positions, Eigen::MatrixXd& jacobian) const;
846 
855  void getMasses(Eigen::VectorXd& masses) const;
856 
860  void getMetadata(std::vector<MetadataBase>& metadata) const;
861 private:
866 };
867 
868 } // namespace robot_model
869 } // namespace hebi
ActuatorType
Definition: robot_model.hpp:222
IKResult solveInverseKinematics(const Eigen::VectorXd &initial_positions, Eigen::VectorXd &result, Args... args) const
Solves for an inverse kinematics solution given a set of objectives.
Definition: robot_model.hpp:722
std::vector< Matrix4d, Eigen::aligned_allocator< Eigen::Matrix4d > > Matrix4dVector
Definition: robot_model.hpp:16
const RigidBodyMetadata * asRigidBody() const
View the rigid body specific fields, if this metadata describes a rigid body.
Definition: robot_model.hpp:340
Link specific view of an element in a RobotModel instance.
Definition: robot_model.hpp:390
void custom_objective_callback_wrapper(void *user_data, size_t num_positions, const double *positions, double *errors)
C-style callback wrapper to call into CustomObjective class; this should only be used by the CustomOb...
Definition: robot_model.hpp:185
const ActuatorMetadata * asActuator() const
View the actuator specific fields, if this metadata describes an actuator.
Definition: robot_model.hpp:292
JointType
Definition: robot_model.hpp:213
JointType jointType() const
Specifies the particular joint type.
Definition: robot_model.hpp:384
LinkType
Definition: robot_model.hpp:234
Definition: arm.cpp:5
const BracketMetadata * asBracket() const
View the bracket specific fields, if this metadata describes a bracket.
Definition: robot_model.hpp:304
BracketType
Definition: robot_model.hpp:249
CustomObjective(ObjectiveCallback error_function)
Definition: robot_model.hpp:142
#define HEBI_DISABLE_COPY_MOVE(Class)
Definition: util.hpp:6
void getJacobians(HebiFrameType frame_type, const Eigen::VectorXd &positions, MatrixXdVector &jacobians) const
Generates the Jacobian for each frame in the given kinematic tree.
Definition: robot_model.hpp:791
ActuatorType actuatorType() const
Specifies the particular actuator model.
Definition: robot_model.hpp:362
Represents a chain or tree of robot elements (rigid bodies and joints).
Definition: robot_model.hpp:419
IKResult solveIK(const Eigen::VectorXd &initial_positions, Eigen::VectorXd &result, Args... objectives) const
Solves for an inverse kinematics solution given a set of objectives.
Definition: robot_model.hpp:742
void getJ(HebiFrameType frame_type, const Eigen::VectorXd &positions, MatrixXdVector &jacobians) const
Generates the Jacobian for each frame in the given kinematic tree.
Definition: robot_model.hpp:816
float twist() const
The twist of the link (e.g., the value specified in invocation of RobotModel::addLink)
Definition: robot_model.hpp:405
Actuator specific view of an element in a RobotModel instance.
Definition: robot_model.hpp:357
ElementType elementType() const
Definition: robot_model.hpp:283
const JointMetadata * asJoint() const
View the joint specific fields, if this metadata describes a joint.
Definition: robot_model.hpp:316
HebiStatusCode result
Definition: robot_model.hpp:21
EndEffectorType
Definition: robot_model.hpp:264
Definition: robot_model.hpp:67
LinkInputType
Definition: robot_model.hpp:239
void getFK(HebiFrameType frame_type, const Eigen::VectorXd &positions, Matrix4dVector &frames) const
Generates the forward kinematics for the given robot model.
Definition: robot_model.hpp:690
Base class for all metadata. Do not instantiate directly.
Definition: robot_model.hpp:274
virtual ~Objective()
Definition: robot_model.hpp:30
Definition: robot_model.hpp:26
size_t getFrameCount(HebiFrameType frame_type) const
Return the number of frames in the forward kinematics.
Definition: robot_model.hpp:528
Definition: robot_model.hpp:46
Rigid Body specific view of an element in a RobotModel instance.
Definition: robot_model.hpp:411
BracketType bracketType() const
Specifies the particular bracket type.
Definition: robot_model.hpp:373
Allows you to add a custom objective function.
Definition: robot_model.hpp:135
Bracket specific view of an element in a RobotModel instance.
Definition: robot_model.hpp:368
void getForwardKinematics(HebiFrameType frame_type, const Eigen::VectorXd &positions, Matrix4dVector &frames) const
Generates the forward kinematics for the given robot model.
Definition: robot_model.hpp:653
Joint specific view of an element in a RobotModel instance.
Definition: robot_model.hpp:379
void callCallback(void *, size_t num_positions, const double *positions, double *errors) const
Definition: robot_model.hpp:147
FrameType
Definition: robot_model.hpp:206
LinkOutputType
Definition: robot_model.hpp:244
Definition: robot_model.hpp:20
std::function< void(const std::vector< double > &, std::array< double, N > &)> ObjectiveCallback
Definition: robot_model.hpp:140
float extension() const
The extension of the link (e.g., the value specified in invocation of RobotModel::addLink)
Definition: robot_model.hpp:400
ElementType
Definition: robot_model.hpp:196
LinkType linkType() const
Specifies the particular link type.
Definition: robot_model.hpp:395
const HebiRobotModelElementMetadata & metadata() const
Definition: robot_model.hpp:349
std::vector< MatrixXd, Eigen::aligned_allocator< Eigen::MatrixXd > > MatrixXdVector
Definition: robot_model.hpp:17
bool addJoint(HebiJointType joint_type)
Adds a degree of freedom about the specified axis.
Definition: robot_model.hpp:569
CustomObjective(double weight, ObjectiveCallback error_function)
Definition: robot_model.hpp:143
const LinkMetadata * asLink() const
View the link specific fields, if this metadata describes a link.
Definition: robot_model.hpp:328