arm.cpp
Go to the documentation of this file.
4 
5 namespace hebi {
6 namespace experimental {
7 namespace arm {
8 
9 std::unique_ptr<Arm> Arm::create(const Arm::Params& params) {
10 
11  // Load the HRDF:
12  std::shared_ptr<robot_model::RobotModel> robot_model;
13  if (params.hrdf_file_.empty())
14  robot_model = params.robot_model_;
15  else
16  robot_model = robot_model::RobotModel::loadHRDF(params.hrdf_file_);
17 
18  if (!robot_model)
19  return nullptr;
20 
21  // Get the group (scope the lookup object so it is destroyed
22  // immediately after the lookup operation)
23  std::shared_ptr<Group> group;
24  {
25  Lookup lookup;
26  group = lookup.getGroupFromNames(params.families_, params.names_);
27  }
28  if (!group) {
29  std::cout << "Could not create arm! Check that family and names match actuators on the network.\n";
30  return nullptr;
31  }
32 
33  // Check sizes
34  if (group->size() != robot_model->getDoFCount()) {
35  std::cout << "HRDF does not have the same number of actuators as group!\n";
36  return nullptr;
37  }
38 
39  // Set parameters
40  if (!group->setCommandLifetimeMs(params.command_lifetime_)) {
41  std::cout << "Could not set command lifetime on group; check that it is valid.\n";
42  return nullptr;
43  }
44  if (!group->setFeedbackFrequencyHz(params.control_frequency_)) {
45  std::cout << "Could not set feedback frequency on group; check that it is valid.\n";
46  return nullptr;
47  }
48 
49  // Try to get feedback -- if we don't get a packet in the first N times,
50  // something is wrong
51  int num_attempts = 0;
52 
53  // We need feedback, so we can plan trajectories if that gets called before the first "update"
54  GroupFeedback feedback(group->size());
55  while (!group->getNextFeedback(feedback)) {
56  if (num_attempts++ > 10) {
57  std::cout << "Could not communicate with robot; check network connection.\n";
58  return nullptr;
59  }
60  }
61 
62  // Note: once ROS moves up to C++14, we can change this to "make_unique".
63  return std::unique_ptr<Arm>(new Arm(params.get_current_time_s_, group, std::move(robot_model), params.end_effector_));
64 }
65 
66 bool Arm::loadGains(const std::string& gains_file)
67 {
68  hebi::GroupCommand gains_cmd(group_->size());
69  if (!gains_cmd.readGains(gains_file))
70  return false;
71 
72  return group_->sendCommandWithAcknowledgement(gains_cmd);
73 }
74 
75 bool Arm::update() {
76  double t = get_current_time_s_();
77 
78  // Time must be monotonically increasing!
79  if (t < last_time_)
80  return false;
81 
82  last_time_ = t;
83 
84  if (!group_->getNextFeedback(feedback_))
85  return false;
86 
87  // Define aux state so end effector can be updated
88  Eigen::VectorXd aux(0);
89 
90  // Update command from trajectory
91  if (trajectory_) {
92  // If we have an active trajectory to our goal, use this.
93  // Note -- this applies even if we are past the end of it;
94  // we just stay with last state.
95  // (trajectory_start_time_ should not be nan here!)
96  double t_traj = t - trajectory_start_time_;
97  t_traj = std::min(t_traj, trajectory_->getDuration());
98  trajectory_->getState(t_traj, &pos_, &vel_, &accel_);
99 
100  aux = getAux(t_traj);
101  } else {
102  pos_.setConstant(std::numeric_limits<double>::quiet_NaN());
103  vel_.setConstant(std::numeric_limits<double>::quiet_NaN());
104  accel_.setConstant(0.0);
105  }
108 
109  // Note -- this could be done just at arm initialization, but end effector
110  // mass/payload may change
111  robot_model_->getMasses(masses_);
112 
114  command_.setEffort(gc_efforts);
115 
116  // TODO: add dynamic-comp efforts
117 
118  // Update end effector if one exists
119  if (end_effector_ && !end_effector_->update(aux))
120  return false;
121 
122  return true;
123 }
124 
125 bool Arm::send() {
126  return group_->sendCommand(command_) && (end_effector_ ? end_effector_->send() : true);
127 }
128 
129 // TODO: think about adding customizability, or at least more intelligence for
130 // the default heuristic.
131 Eigen::VectorXd getWaypointTimes(
132  const Eigen::MatrixXd& positions,
133  const Eigen::MatrixXd& velocities,
134  const Eigen::MatrixXd& accelerations) {
135 
136  double rampTime = 1.2;
137 
138  size_t num_waypoints = positions.cols();
139 
140  Eigen::VectorXd times(num_waypoints);
141  for (size_t i = 0; i < num_waypoints; ++i)
142  times[i] = rampTime * (double)i;
143 
144  return times;
145 }
146 
147 void Arm::setGoal(const Goal& goal) {
148  int num_joints = goal.positions().rows();
149 
150  // If there is a current trajectory, use the commands as a starting point;
151  // if not, replan from current feedback.
152  Eigen::VectorXd curr_pos = Eigen::VectorXd::Zero(num_joints);
153  Eigen::VectorXd curr_vel = Eigen::VectorXd::Zero(num_joints);
154  Eigen::VectorXd curr_accel = Eigen::VectorXd::Zero(num_joints);
155 
156  // Replan if these is a current trajectory:
157  if (trajectory_) {
158  double t_traj = last_time_ - trajectory_start_time_;
159  t_traj = std::min(t_traj, trajectory_->getDuration());
160  trajectory_->getState(t_traj, &curr_pos, &curr_vel, &curr_accel);
161  } else {
162  curr_pos = feedback_.getPosition();
163  curr_vel = feedback_.getVelocity();
164  // (accelerations remain zero)
165  }
166 
167  int num_waypoints = goal.positions().cols() + 1;
168 
169  Eigen::MatrixXd positions(num_joints, num_waypoints);
170  Eigen::MatrixXd velocities(num_joints, num_waypoints);
171  Eigen::MatrixXd accelerations(num_joints, num_waypoints);
172 
173  // Initial state
174  positions.col(0) = curr_pos;
175  velocities.col(0) = curr_vel;
176  accelerations.col(0) = curr_accel;
177 
178  // Copy new waypoints
179  positions.rightCols(num_waypoints - 1) = goal.positions();
180  velocities.rightCols(num_waypoints - 1) = goal.velocities();
181  accelerations.rightCols(num_waypoints - 1) = goal.accelerations();
182 
183  // Get waypoint times
184  Eigen::VectorXd waypoint_times(num_waypoints);
185  // If time vector is empty, automatically determine times
186  if (goal.times().size() == 0) {
187  waypoint_times = getWaypointTimes(positions, velocities, accelerations);
188  } else {
189  waypoint_times(0) = 0;
190  waypoint_times.tail(num_waypoints - 1) = goal.times();
191  }
192 
193  // Create new trajectory
195  waypoint_times, positions, &velocities, &accelerations);
197 
198  // Update aux state:
199  if (goal.aux().rows() > 0 && (goal.aux().cols() + 1) == num_waypoints) {
200  aux_.resize(goal.aux().rows(), goal.aux().cols() + 1);
201  aux_.col(0).setConstant(std::numeric_limits<double>::quiet_NaN());
202  aux_.rightCols(num_waypoints - 1) = goal.aux();
203  aux_times_ = waypoint_times;
204  } else {
205  // Reset aux states!
206  aux_.resize(0, 0);
207  aux_times_.resize(0);
208  }
209 }
210 
211 double Arm::goalProgress() const {
212  if (trajectory_) {
213  double t_traj = last_time_ - trajectory_start_time_;
214  t_traj = std::min(t_traj, trajectory_->getDuration());
215  return t_traj / trajectory_->getDuration();
216  }
217  // No current goal!
218  return 0.0;
219 }
220 
222  trajectory_ = nullptr;
223  trajectory_start_time_ = std::numeric_limits<double>::quiet_NaN();
224 }
225 
226 Eigen::VectorXd Arm::getAux(double t) const {
227  Eigen::VectorXd res;
228  if (aux_times_.size() == 0 || aux_.cols() != aux_times_.size() || aux_.rows() == 0)
229  return Eigen::VectorXd();
230 
231  // Find the first time
232  // TODO: use a tracer for performance here...or at least a std::upper_bound/etc.
233  for (int i = aux_times_.size() - 1; i >= 0; --i) {
234  if (t >= aux_times_[i]) {
235  return aux_.col(i);
236  }
237  }
238 
239  // Note -- should never get here...should always be at least as big as the initial t == 0...
240  return aux_.col(0);
241 }
242 
243 } // namespace arm
244 } // namespace experimental
245 } // namespace hebi
const Eigen::MatrixXd & accelerations() const
Definition: goal.hpp:163
A list of Feedback objects that can be received from a Group of modules; the size() must match the nu...
const Eigen::MatrixXd & positions() const
Definition: goal.hpp:161
std::shared_ptr< robot_model::RobotModel > robot_model_
Definition: arm.hpp:290
std::shared_ptr< robot_model::RobotModel > robot_model_
Definition: arm.hpp:63
double goalProgress() const
Definition: arm.cpp:211
const Eigen::MatrixXd & aux() const
Definition: goal.hpp:164
static Eigen::VectorXd getGravCompEfforts(const hebi::robot_model::RobotModel &model, const Eigen::VectorXd &masses, const hebi::GroupFeedback &feedback)
Definition: grav_comp.hpp:14
static std::shared_ptr< Trajectory > createUnconstrainedQp(const VectorXd &time_vector, const MatrixXd &positions, const MatrixXd *velocities=nullptr, const MatrixXd *accelerations=nullptr)
Creates a smooth trajectory through a set of waypoints (position velocity and accelerations defined a...
Definition: trajectory.cpp:14
const Eigen::MatrixXd & velocities() const
Definition: goal.hpp:162
std::shared_ptr< trajectory::Trajectory > trajectory_
Definition: arm.hpp:294
Definition: arm.cpp:5
Eigen::VectorXd getVelocity() const
Convenience function for returning feedback velocity values.
static std::unique_ptr< RobotModel > loadHRDF(const std::string &file)
Creates a robot model object with no bodies and an identity base frame.
Definition: robot_model.cpp:97
std::function< double()> get_current_time_s_
Definition: arm.hpp:287
const Group & group() const
Definition: arm.hpp:97
Eigen::VectorXd getWaypointTimes(const Eigen::MatrixXd &positions, const Eigen::MatrixXd &velocities, const Eigen::MatrixXd &accelerations)
Definition: arm.cpp:131
Eigen::VectorXd vel_
Definition: arm.hpp:299
static std::unique_ptr< Arm > create(const Params &params)
Definition: arm.cpp:9
std::shared_ptr< EndEffectorBase > end_effector_
Definition: arm.hpp:291
Eigen::VectorXd getAux(double t) const
Definition: arm.cpp:226
Eigen::MatrixXd aux_
Definition: arm.hpp:308
Eigen::VectorXd pos_
Definition: arm.hpp:298
Eigen::VectorXd accel_
Definition: arm.hpp:300
A list of Command objects appropriate for sending to a Group of modules; the size() must match the nu...
std::shared_ptr< Group > group_
Definition: arm.hpp:289
Eigen::VectorXd masses_
Definition: arm.hpp:303
std::function< double()> get_current_time_s_
Definition: arm.hpp:73
Maintains a registry of network-connected modules and returns Group objects to the user...
Definition: lookup.hpp:24
void setVelocity(const Eigen::VectorXd &velocity)
Convenience function for setting velocity commands from Eigen vectors.
bool loadGains(const std::string &gains_file)
Definition: arm.cpp:66
void setGoal(const Goal &goal)
Definition: arm.cpp:147
void setPosition(const Eigen::VectorXd &position)
Convenience function for setting position commands from Eigen vectors.
std::vector< std::string > names_
Definition: arm.hpp:54
hebi::GroupFeedback feedback_
Definition: arm.hpp:313
void setEffort(const Eigen::VectorXd &effort)
Convenience function for setting effort commands from Eigen vectors.
std::vector< std::string > families_
Definition: arm.hpp:53
Arm(std::function< double()> get_current_time_s, std::shared_ptr< Group > group, std::shared_ptr< robot_model::RobotModel > robot_model, std::shared_ptr< EndEffectorBase > end_effector=nullptr)
Definition: arm.hpp:269
const Eigen::VectorXd & times() const
Definition: goal.hpp:160
Eigen::VectorXd aux_times_
Definition: arm.hpp:307
hebi::GroupCommand command_
Definition: arm.hpp:314
std::shared_ptr< EndEffectorBase > end_effector_
Definition: arm.hpp:67
std::shared_ptr< Group > getGroupFromNames(const std::vector< std::string > &families, const std::vector< std::string > &names, int32_t timeout_ms=DEFAULT_TIMEOUT)
Get a group from modules with the given names and families.
Definition: lookup.cpp:11
Eigen::VectorXd getPosition() const
Convenience function for returning feedback position values.


hebi_cpp_api_ros
Author(s): Chris Bollinger , Matthew Tesch
autogenerated on Thu May 28 2020 03:14:44