HEBI C++ API  3.16.0
goal.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <Eigen/Dense>
4 #include "trajectory.hpp"
5 
6 namespace hebi {
7 namespace arm {
8 
9 // A class that specifies a goal position of one or more waypoint and/or
10 // auxilary states.
11 // Static create methods are provided for various cases; in the case that
12 // velocities or accelerations are omitted, the default behavior is to leave
13 // these unconstrained except for a final "0" state. For aux states, this is
14 // left as unchanged. For times, this is left to the Arm object to fill in a
15 // heuristic.
16 class Goal {
17 
18 public:
20  // Single waypoint static create functions
22 
23  // Single waypoint, default vel/accel, no time
24  static Goal createFromPosition(const Eigen::VectorXd& positions) {
25  return Goal(Eigen::VectorXd(0),
26  toMatrix(positions),
27  nanWithZeroRight(positions.size(), 1),
28  nanWithZeroRight(positions.size(), 1),
29  Eigen::MatrixXd(0, 0));
30  }
31 
32  // Single waypoint, default vel/accel
33  static Goal createFromPosition(double time, const Eigen::VectorXd& positions) {
34  return Goal(toVector(time),
35  toMatrix(positions),
36  nanWithZeroRight(positions.size(), 1),
37  nanWithZeroRight(positions.size(), 1),
38  Eigen::MatrixXd(0, 0));
39  }
40 
41  // Single waypoint, default accel, no time
42  static Goal createFromWaypoint(const Eigen::VectorXd& positions,
43  const Eigen::VectorXd& velocities) {
44  return Goal(Eigen::VectorXd(0),
45  toMatrix(positions),
46  toMatrix(velocities),
47  nanWithZeroRight(positions.size(), 1),
48  Eigen::MatrixXd(0, 0));
49  }
50 
51  // Single waypoint, default accel
52  static Goal createFromWaypoint(double time,
53  const Eigen::VectorXd& positions,
54  const Eigen::VectorXd& velocities) {
55  return Goal(toVector(time),
56  toMatrix(positions),
57  toMatrix(velocities),
58  nanWithZeroRight(positions.size(), 1),
59  Eigen::MatrixXd(0, 0));
60  }
61 
62  // Single waypoint, no time
63  static Goal createFromWaypoint(const Eigen::VectorXd& positions,
64  const Eigen::VectorXd& velocities,
65  const Eigen::VectorXd& accelerations) {
66  return Goal(Eigen::VectorXd(0),
67  toMatrix(positions),
68  toMatrix(velocities),
69  toMatrix(accelerations),
70  Eigen::MatrixXd(0, 0));
71  }
72 
73  // Single waypoint
74  static Goal createFromWaypoint(double time,
75  const Eigen::VectorXd& positions,
76  const Eigen::VectorXd& velocities,
77  const Eigen::VectorXd& accelerations) {
78  return Goal(toVector(time),
79  toMatrix(positions),
80  toMatrix(velocities),
81  toMatrix(accelerations),
82  Eigen::MatrixXd(0, 0));
83  }
84 
85  // Single waypoint + aux state, default vel/accel, no time
86  static Goal createFromPositionWithAux(const Eigen::VectorXd& positions,
87  const Eigen::VectorXd& aux) {
88  return Goal(Eigen::VectorXd(0),
89  toMatrix(positions),
90  nanWithZeroRight(positions.size(), 1),
91  nanWithZeroRight(positions.size(), 1),
92  toMatrix(aux));
93  }
94 
95  // Single waypoint + aux state, default vel/accel
96  static Goal createFromPositionWithAux(double time,
97  const Eigen::VectorXd& positions,
98  const Eigen::VectorXd& aux) {
99  return Goal(toVector(time),
100  toMatrix(positions),
101  nanWithZeroRight(positions.size(), 1),
102  nanWithZeroRight(positions.size(), 1),
103  toMatrix(aux));
104  }
105 
106  // Single waypoint + aux state, default accel, no time
107  static Goal createFromWaypointWithAux(const Eigen::VectorXd& positions,
108  const Eigen::VectorXd& velocities,
109  const Eigen::VectorXd& aux) {
110  return Goal(Eigen::VectorXd(0),
111  toMatrix(positions),
112  toMatrix(velocities),
113  nanWithZeroRight(positions.size(), 1),
114  toMatrix(aux));
115  }
116 
117  // Single waypoint + aux state, default accel
118  static Goal createFromWaypointWithAux(double time,
119  const Eigen::VectorXd& positions,
120  const Eigen::VectorXd& velocities,
121  const Eigen::VectorXd& aux) {
122  return Goal(toVector(time),
123  toMatrix(positions),
124  toMatrix(velocities),
125  nanWithZeroRight(positions.size(), 1),
126  toMatrix(aux));
127  }
128 
129  // Single waypoint + aux state, no time
130  static Goal createFromWaypointWithAux(const Eigen::VectorXd& positions,
131  const Eigen::VectorXd& velocities,
132  const Eigen::VectorXd& accelerations,
133  const Eigen::VectorXd& aux) {
134  return Goal(Eigen::VectorXd(0),
135  toMatrix(positions),
136  toMatrix(velocities),
137  toMatrix(accelerations),
138  toMatrix(aux));
139  }
140 
141  // Single waypoint + aux state
142  static Goal createFromWaypointWithAux(double time,
143  const Eigen::VectorXd& positions,
144  const Eigen::VectorXd& velocities,
145  const Eigen::VectorXd& accelerations,
146  const Eigen::VectorXd& aux) {
147  return Goal(toVector(time),
148  toMatrix(positions),
149  toMatrix(velocities),
150  toMatrix(accelerations),
151  toMatrix(aux));
152  }
153 
155  // Multiple waypoint static create functions
157 
158  // Multiple waypoints, default vel/accel, no time
159  static Goal createFromPositions(const Eigen::MatrixXd& positions) {
160  return Goal(Eigen::VectorXd(0),
161  positions,
162  nanWithZeroRight(positions.rows(), positions.cols()),
163  nanWithZeroRight(positions.rows(), positions.cols()),
164  Eigen::MatrixXd(0, 0));
165  }
166 
167  // Multiple waypoints, default vel/accel
168  static Goal createFromPositions(const Eigen::VectorXd& times,
169  const Eigen::MatrixXd& positions) {
170  return Goal(times,
171  positions,
172  nanWithZeroRight(positions.rows(), positions.cols()),
173  nanWithZeroRight(positions.rows(), positions.cols()),
174  Eigen::MatrixXd(0, 0));
175  }
176 
177  // Multiple waypoints, default accel, no time
178  static Goal createFromWaypoints(const Eigen::MatrixXd& positions,
179  const Eigen::MatrixXd& velocities) {
180  return Goal(Eigen::VectorXd(0),
181  positions,
182  velocities,
183  nanWithZeroRight(positions.rows(), positions.cols()),
184  Eigen::MatrixXd(0, 0));
185  }
186 
187  // Multiple waypoints, default accel
188  static Goal createFromWaypoints(const Eigen::VectorXd& times,
189  const Eigen::MatrixXd& positions,
190  const Eigen::MatrixXd& velocities) {
191  return Goal(times,
192  positions,
193  velocities,
194  nanWithZeroRight(positions.rows(), positions.cols()),
195  Eigen::MatrixXd(0, 0));
196  }
197 
198  // Multiple waypoints, no time
199  static Goal createFromWaypoints(const Eigen::MatrixXd& positions,
200  const Eigen::MatrixXd& velocities,
201  const Eigen::MatrixXd& accelerations) {
202  return Goal(Eigen::VectorXd(0),
203  positions,
204  velocities,
206  Eigen::MatrixXd(0, 0));
207  }
208 
209  // Multiple waypoints
210  static Goal createFromWaypoints(const Eigen::VectorXd& times,
211  const Eigen::MatrixXd& positions,
212  const Eigen::MatrixXd& velocities,
213  const Eigen::MatrixXd& accelerations) {
214  return Goal(times,
215  positions,
216  velocities,
218  Eigen::MatrixXd(0, 0));
219  }
220 
221  // Multiple waypoints + aux state, default vel/accel, no time
222  static Goal createFromPositionsWithAux(const Eigen::MatrixXd& positions,
223  const Eigen::MatrixXd& aux) {
224  return Goal(Eigen::VectorXd(0),
225  positions,
226  nanWithZeroRight(positions.rows(), positions.cols()),
227  nanWithZeroRight(positions.rows(), positions.cols()),
228  aux);
229  }
230 
231  // Multiple waypoints + aux state, default vel/accel
232  static Goal createFromPositionsWithAux(const Eigen::VectorXd& times,
233  const Eigen::MatrixXd& positions,
234  const Eigen::MatrixXd& aux) {
235  return Goal(times,
236  positions,
237  nanWithZeroRight(positions.rows(), positions.cols()),
238  nanWithZeroRight(positions.rows(), positions.cols()),
239  aux);
240  }
241 
242  // Multiple waypoints + aux state, default accel, no time
243  static Goal createFromWaypointsWithAux(const Eigen::MatrixXd& positions,
244  const Eigen::MatrixXd& velocities,
245  const Eigen::MatrixXd& aux) {
246  return Goal(Eigen::VectorXd(0),
247  positions,
248  velocities,
249  nanWithZeroRight(positions.rows(), positions.cols()),
250  aux);
251  }
252 
253  // Multiple waypoints + aux state, default accel
254  static Goal createFromWaypointsWithAux(const Eigen::VectorXd& times,
255  const Eigen::MatrixXd& positions,
256  const Eigen::MatrixXd& velocities,
257  const Eigen::MatrixXd& aux) {
258  return Goal(times,
259  positions,
260  velocities,
261  nanWithZeroRight(positions.rows(), positions.cols()),
262  aux);
263  }
264 
265  // Multiple waypoints + aux state, no time
266  static Goal createFromWaypointsWithAux(const Eigen::MatrixXd& positions,
267  const Eigen::MatrixXd& velocities,
268  const Eigen::MatrixXd& accelerations,
269  const Eigen::MatrixXd& aux) {
270  return Goal(Eigen::VectorXd(0),
271  positions,
272  velocities,
274  aux);
275  }
276 
277  // Multiple waypoints + aux state
278  static Goal createFromWaypointsWithAux(const Eigen::VectorXd& times,
279  const Eigen::MatrixXd& positions,
280  const Eigen::MatrixXd& velocities,
281  const Eigen::MatrixXd& accelerations,
282  const Eigen::MatrixXd& aux) {
283  return Goal(times,
284  positions,
285  velocities,
287  aux);
288  }
289 
290  const Eigen::VectorXd& times() const { return times_; }
291  const Eigen::MatrixXd& positions() const { return positions_; }
292  const Eigen::MatrixXd& velocities() const { return velocities_; }
293  const Eigen::MatrixXd& accelerations() const { return accelerations_; }
294  const Eigen::MatrixXd& aux() const { return aux_; }
295 
296  // Build a trajectory that is continuous from the current arm state
297  // If "start_vel" is null, assumed to be zero
298  // If "start_acc" is null, assumed to be zero
299  // If "vel_limits" is null, assumed to be unconstrained
300  // If "accel_limits" is null, assumed to be unconstrained
301  std::tuple<std::shared_ptr<hebi::trajectory::Trajectory>, Eigen::MatrixXd, Eigen::VectorXd> buildTrajectoryFrom(const Eigen::VectorXd& start_pos,
302  const Eigen::VectorXd* start_vel,
303  const Eigen::VectorXd* start_accel,
304  const Eigen::VectorXd* vel_limits = nullptr,
305  const Eigen::VectorXd* accel_limits = nullptr) const {
306 
307  const auto num_joints = positions_.rows();
308  auto num_waypoints = positions_.cols() + 1;
309  if (start_pos.size() != num_joints) {
310  throw std::invalid_argument("start positions size must match number of joints in Goal object");
311  } else if (start_vel != nullptr && start_vel->size() != num_joints) {
312  throw std::invalid_argument("start velocities size must match number of joints in Goal object");
313  } else if (start_accel != nullptr && start_accel->size() != num_joints) {
314  throw std::invalid_argument("start accelerations size must match number of joints in Goal object");
315  } else if (vel_limits != nullptr && vel_limits->size() != num_joints) {
316  throw std::invalid_argument("velocity limits size must match number of joints in Goal object");
317  } else if (accel_limits != nullptr && accel_limits->size() != num_joints) {
318  throw std::invalid_argument("acceleration limits size must match number of joints in Goal object");
319  }
320 
321  // Note -- in future, we can call heuristics from API here
322  auto getWaypointTimes = [](const Eigen::MatrixXd& positions, const Eigen::MatrixXd& /*velocities*/,
323  const Eigen::MatrixXd& /*accelerations*/) {
324  double rampTime = 1.2;
325 
326  size_t num_waypoints = positions.cols();
327 
328  Eigen::VectorXd times(num_waypoints);
329  for (size_t i = 0; i < num_waypoints; ++i)
330  times[i] = rampTime * (double)i;
331 
332  return times;
333  };
334 
335  // Start with provided velocity and acceleration, or default to zero
336  Eigen::VectorXd curr_vel = Eigen::VectorXd::Zero(num_joints);
337  Eigen::VectorXd curr_accel = Eigen::VectorXd::Zero(num_joints);
338  if (start_vel)
339  curr_vel = *start_vel;
340  if (start_accel)
341  curr_accel = *start_accel;
342 
343  Eigen::MatrixXd positions(num_joints, num_waypoints);
344  Eigen::MatrixXd velocities(num_joints, num_waypoints);
345  Eigen::MatrixXd accelerations(num_joints, num_waypoints);
346 
347  // Initial state
348  positions.col(0) = start_pos;
349  velocities.col(0) = curr_vel;
350  accelerations.col(0) = curr_accel;
351 
352  // Copy new waypoints
353  positions.rightCols(num_waypoints - 1) = positions_;
354  velocities.rightCols(num_waypoints - 1) = velocities_;
355  accelerations.rightCols(num_waypoints - 1) = accelerations_;
356 
357  // Get waypoint times
358  Eigen::VectorXd waypoint_times(num_waypoints);
359  // If time vector is empty, automatically determine times
360  if (times_.size() == 0) {
361  waypoint_times = getWaypointTimes(positions, velocities, accelerations); // TODO: reference??!?
362  } else {
363  waypoint_times(0) = 0;
364  waypoint_times.tail(num_waypoints - 1) = times_;
365  }
366 
367  // Create new trajectory
368  auto trajectory =
370 
371  // Apply limits and rescale if necessary
372  double vel_scaling = 1.0, accel_scaling = 1.0;
373  if (vel_limits != nullptr) {
374  // Convert nan to inf
375  Eigen::VectorXd vel_lim = vel_limits->unaryExpr([](double x) {
376  return std::isnan(x) ? std::numeric_limits<double>::infinity() : x;
377  });
378 
379  // Get current max velocity
380  Eigen::VectorXd max_vel(num_joints);
381  trajectory->getMaxVelocity(max_vel);
382 
383  // Determine scaling factor using vectorized operations
384  vel_scaling = (max_vel.array() / vel_lim.array()).eval().maxCoeff();
385  vel_scaling = std::max(vel_scaling, 1.0);
386  }
387  if (accel_limits != nullptr) {
388  // Convert nan to inf
389  Eigen::VectorXd accel_lim = accel_limits->unaryExpr([](double x) {
390  return std::isnan(x) ? std::numeric_limits<double>::infinity() : x;
391  });
392 
393  // Get current max acceleration
394  Eigen::VectorXd max_acc(num_joints);
395  trajectory->getMaxAcceleration(max_acc);
396 
397  // Determine scaling factor using vectorized operations
398  accel_scaling = (max_acc.array() / accel_lim.array()).eval().maxCoeff();
399  accel_scaling = std::sqrt(std::max(accel_scaling, 1.0));
400  }
401 
402  if (vel_scaling > 1.0 || accel_scaling > 1.0) {
403  double scaling_factor = std::max(vel_scaling, accel_scaling);
404  trajectory->rescale(scaling_factor);
405  }
406 
407  Eigen::MatrixXd aux(0,0);
408  Eigen::VectorXd aux_times(0);
409 
410  // Update aux state:
411  if (aux_.rows() > 0 && (aux_.cols() + 1) == num_waypoints) {
412  aux.resize(aux_.rows(), aux_.cols() + 1);
413  aux.col(0).setConstant(std::numeric_limits<double>::quiet_NaN());
414  aux.rightCols(num_waypoints - 1) = aux_;
415  aux_times = waypoint_times;
416  }
417 
418  return {trajectory, aux, aux_times};
419  }
420 
421 private:
422 
423  Goal(const Eigen::VectorXd& times,
424  const Eigen::MatrixXd& positions,
425  const Eigen::MatrixXd& velocities,
426  const Eigen::MatrixXd& accelerations,
427  const Eigen::MatrixXd& aux)
428  : times_(times),
429  positions_(positions),
430  velocities_(velocities),
431  accelerations_(accelerations),
432  aux_(aux) {
433  if (positions_.rows() != velocities_.rows() || positions_.rows() != accelerations_.rows() ||
434  positions_.cols() != velocities_.cols() || positions_.cols() != accelerations_.cols())
435  throw std::invalid_argument("Goal must have consistent position/velocity/acceleration sizes");
436  if (aux_.cols() != 0 && positions_.cols() != aux_.cols())
437  throw std::invalid_argument("Goal must have empty aux or aux consistent with number of waypoints");
438  }
439 
440  // Helper function to create unconstrained points along a motion, with nan at the right side.
441  static Eigen::MatrixXd nanWithZeroRight(size_t num_joints, size_t num_waypoints) {
442  double nan = std::numeric_limits<double>::quiet_NaN();
443  Eigen::MatrixXd matrix(num_joints, num_waypoints);
444  matrix.setConstant(nan);
445  matrix.rightCols<1>().setZero();
446  return matrix;
447  }
448 
449  static Eigen::VectorXd toVector(double scalar) {
450  Eigen::VectorXd vector(1);
451  vector[0] = scalar;
452  return vector;
453  }
454 
455  static Eigen::MatrixXd toMatrix(const Eigen::VectorXd& vector) {
456  Eigen::MatrixXd matrix(vector.size(), 1);
457  matrix.col(0) = vector;
458  return matrix;
459  }
460 
461  const Eigen::VectorXd times_{0};
462  const Eigen::MatrixXd positions_{0, 0};
463  const Eigen::MatrixXd velocities_{0, 0};
464  const Eigen::MatrixXd accelerations_{0, 0};
465  const Eigen::MatrixXd aux_{0, 0};
466 };
467 
468 } // namespace arm
469 } // namespace hebi
static Goal createFromPositions(const Eigen::VectorXd &times, const Eigen::MatrixXd &positions)
Definition: goal.hpp:168
static Goal createFromPositionWithAux(const Eigen::VectorXd &positions, const Eigen::VectorXd &aux)
Definition: goal.hpp:86
static Goal createFromWaypoint(const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &accelerations)
Definition: goal.hpp:63
static Goal createFromWaypoint(double time, const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &accelerations)
Definition: goal.hpp:74
static Goal createFromPositionsWithAux(const Eigen::VectorXd &times, const Eigen::MatrixXd &positions, const Eigen::MatrixXd &aux)
Definition: goal.hpp:232
static Goal createFromWaypointsWithAux(const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &aux)
Definition: goal.hpp:243
static Goal createFromWaypoints(const Eigen::VectorXd &times, const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities)
Definition: goal.hpp:188
Definition: arm.cpp:10
const Eigen::MatrixXd & positions() const
Definition: goal.hpp:291
static Goal createFromWaypointWithAux(double time, const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &accelerations, const Eigen::VectorXd &aux)
Definition: goal.hpp:142
static Goal createFromWaypointWithAux(double time, const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &aux)
Definition: goal.hpp:118
static Goal createFromPosition(const Eigen::VectorXd &positions)
Definition: goal.hpp:24
std::tuple< std::shared_ptr< hebi::trajectory::Trajectory >, Eigen::MatrixXd, Eigen::VectorXd > buildTrajectoryFrom(const Eigen::VectorXd &start_pos, const Eigen::VectorXd *start_vel, const Eigen::VectorXd *start_accel, const Eigen::VectorXd *vel_limits=nullptr, const Eigen::VectorXd *accel_limits=nullptr) const
Definition: goal.hpp:301
static Goal createFromWaypointsWithAux(const Eigen::VectorXd &times, const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &accelerations, const Eigen::MatrixXd &aux)
Definition: goal.hpp:278
Definition: arm.cpp:11
static Goal createFromWaypointsWithAux(const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &accelerations, const Eigen::MatrixXd &aux)
Definition: goal.hpp:266
static Goal createFromWaypoints(const Eigen::VectorXd &times, const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &accelerations)
Definition: goal.hpp:210
static Goal createFromWaypoint(const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities)
Definition: goal.hpp:42
const Eigen::VectorXd & times() const
Definition: goal.hpp:290
static Goal createFromPositionWithAux(double time, const Eigen::VectorXd &positions, const Eigen::VectorXd &aux)
Definition: goal.hpp:96
const Eigen::MatrixXd & accelerations() const
Definition: goal.hpp:293
const Eigen::MatrixXd & aux() const
Definition: goal.hpp:294
static Goal createFromWaypoint(double time, const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities)
Definition: goal.hpp:52
static Goal createFromPositions(const Eigen::MatrixXd &positions)
Definition: goal.hpp:159
static Goal createFromWaypoints(const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities)
Definition: goal.hpp:178
static Goal createFromWaypointsWithAux(const Eigen::VectorXd &times, const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &aux)
Definition: goal.hpp:254
static Goal createFromPositionsWithAux(const Eigen::MatrixXd &positions, const Eigen::MatrixXd &aux)
Definition: goal.hpp:222
static Goal createFromWaypointWithAux(const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &aux)
Definition: goal.hpp:107
static Goal createFromWaypoints(const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &accelerations)
Definition: goal.hpp:199
static Goal createFromPosition(double time, const Eigen::VectorXd &positions)
Definition: goal.hpp:33
static std::shared_ptr< Trajectory > createUnconstrainedQp(const Eigen::VectorXd &time_vector, const Eigen::MatrixXd &positions, const Eigen::MatrixXd *velocities=nullptr, const Eigen::MatrixXd *accelerations=nullptr)
Creates a smooth trajectory through a set of waypoints (position velocity and accelerations defined a...
Definition: trajectory.cpp:17
Definition: goal.hpp:16
const Eigen::MatrixXd & velocities() const
Definition: goal.hpp:292
static Goal createFromWaypointWithAux(const Eigen::VectorXd &positions, const Eigen::VectorXd &velocities, const Eigen::VectorXd &accelerations, const Eigen::VectorXd &aux)
Definition: goal.hpp:130