Tetrapod Project
single_leg_plugin.cpp
Go to the documentation of this file.
1 /*******************************************************************/
2 /* AUTHOR: Paal Arthur S. Thorseth & Adrian B. Ghansah */
3 /* ORGN: Dept of Eng Cybernetics, NTNU Trondheim */
4 /* FILE: single_leg_plugin.cpp */
5 /* DATE: Feb 4, 2021 */
6 /* */
7 /* Copyright (C) 2021 Paal Arthur S. Thorseth, */
8 /* Adrian B. Ghansah */
9 /* */
10 /* This program is free software: you can redistribute it */
11 /* and/or modify it under the terms of the GNU General */
12 /* Public License as published by the Free Software Foundation, */
13 /* either version 3 of the License, or (at your option) any */
14 /* later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty */
18 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
19 /* See the GNU General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU General Public */
22 /* License along with this program. If not, see */
23 /* <https://www.gnu.org/licenses/>. */
24 /* */
25 /*******************************************************************/
26 
27 
29 
30 
31 namespace gazebo {
32 
33 // Constructor
35 
36 // Destructor
38 {
39  this->rosNode->shutdown();
40 
41  this->rosProcessQueue.clear();
42  this->rosProcessQueue.disable();
43  this->rosProcessQueueThread.join();
44 
45  this->rosPublishQueue.clear();
46  this->rosPublishQueue.disable();
47  this->rosPublishQueueThread.join();
48 }
49 
50 // Load Plugin
51 void SingleLegPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
52 {
53  // Store model pointer
54  this->model = _model;
55 
56  // Store world pointer
57  this->world = _model->GetWorld();
58 
59  // Store model name
60  this->model_name = _model->GetName();
61  // ROS_INFO_STREAM("Model name: " << model_name); TODO REMOVE
62 
63  // Store base link
64  this->base = _model->GetLink(this->model_name + "::single_leg::sliding_base"); // SDF uses sliding base instead of body
65 
66  // Store joints
67  this->joints = this->model->GetJointController()->GetJoints();
68  //printMap(joints); TODO remove
69 
70  for (auto& t: joints)
71  {
72  ROS_INFO_STREAM(t.first);
73  }
74 
75  // Initialize ROS
76  InitRos();
77 
78  // Load parameters from config
79  if (!LoadParametersRos())
80  {
81  ROS_ERROR("Could not load parameters.");
82  return;
83  }
84 
85  // Setup Joint Controllers
87 
88  // Configure initial joint states
90 
91  // Initialize ROS Queue Threads
93 }
94 
95 // Get base pose
96 Eigen::Matrix<double, 6, 1> SingleLegPlugin::GetBasePose()
97 {
98  ignition::math::Pose3d base_pose = this->base->WorldPose();
99 
100  Eigen::Matrix<double, 6, 1> q_b;
101 
102  q_b(0) = base_pose.X();
103  q_b(1) = base_pose.Y();
104  q_b(2) = base_pose.Z();
105  q_b(3) = base_pose.Roll();
106  q_b(4) = base_pose.Pitch();
107  q_b(5) = base_pose.Yaw();
108 
109  return q_b;
110 }
111 
112 // Get base twist
113 Eigen::Matrix<double, 6, 1> SingleLegPlugin::GetBaseTwist()
114 {
115  ignition::math::Vector3d base_linear_velocity = this->base->WorldLinearVel();
116 
117  ignition::math::Vector3d base_angular_velocity = this->base->WorldAngularVel();
118 
119  Eigen::Matrix<double, 6, 1> u_b;
120 
121  u_b(0) = base_linear_velocity.X();
122  u_b(1) = base_linear_velocity.Y();
123  u_b(2) = base_linear_velocity.Z();
124  u_b(3) = base_angular_velocity.X();
125  u_b(4) = base_angular_velocity.Y();
126  u_b(5) = base_angular_velocity.Z();
127 
128  return u_b;
129 }
130 
131 // Get joint force at _joint_name
132 // TODO Implement.
133 double SingleLegPlugin::GetJointForce(const std::string &_joint_name)
134 {
135  //this->joints[joint_name]->
136  double force = this->joints[this->model_name + "::" + _joint_name]->GetForce(0);
137 
138  return force;
139 }
140 
141 // Get joint forces
142 Eigen::Matrix<double, 3, 1> SingleLegPlugin::GetJointForces()
143 {
144  Eigen::Matrix<double, 3, 1> tau_r;
145 
146  tau_r(0) = this->GetJointForce(this->joint_names[0]);
147  tau_r(1) = this->GetJointForce(this->joint_names[1]);
148  tau_r(2) = this->GetJointForce(this->joint_names[2]);
149 
150  return tau_r;
151 }
152 
153 // Get joint velocity at _joint_name
154 double SingleLegPlugin::GetJointVelocity(const std::string &_joint_name)
155 {
156  double vel = this->joints[this->model_name + "::" + _joint_name]->GetVelocity(0);
157 
158  return vel;
159 }
160 
161 // Get joint velocities
162 Eigen::Matrix<double, 3, 1> SingleLegPlugin::GetJointVelocities()
163 {
164  Eigen::Matrix<double, 3, 1> dot_q_r;
165 
166  dot_q_r(0) = this->GetJointVelocity(this->joint_names[0]);
167  dot_q_r(1) = this->GetJointVelocity(this->joint_names[1]);
168  dot_q_r(2) = this->GetJointVelocity(this->joint_names[2]);
169 
170  return dot_q_r;
171 }
172 
173 // Get joint position at _joint_name
174 double SingleLegPlugin::GetJointPosition(const std::string &_joint_name)
175 {
176  double pos = this->joints[this->model_name + "::" + _joint_name]->Position();
177 
178  return pos;
179 }
180 
181 // Get joint positions
182 Eigen::Matrix<double, 3, 1> SingleLegPlugin::GetJointPositions()
183 {
184  Eigen::Matrix<double, 3, 1> q_r;
185 
186  q_r(0) = this->GetJointPosition(this->joint_names[0]);
187  q_r(1) = this->GetJointPosition(this->joint_names[1]);
188  q_r(2) = this->GetJointPosition(this->joint_names[2]);
189 
190  return q_r;
191 }
192 
193 
194 // Apply force at a single joint
195 void SingleLegPlugin::SetJointForce(const std::string &_joint_name, const double &_force)
196 {
197  this->model->GetJointController()->SetForce(
198  this->model_name + "::" + _joint_name,
199  _force
200  );
201 }
202 
203 // Apply joint forces
204 void SingleLegPlugin::SetJointForces(const std::vector<double> &_forces)
205 {
206  auto start = std::chrono::steady_clock::now();
207 
208  if (this->controlMode != 3)
209  {
210  this->model->GetJointController()->Reset();
211 
213  }
214 
215  for (size_t i = 0; i < this->joint_names.size(); i++)
216  {
217  this->model->GetJointController()->SetForce(
218  this->model_name + "::" + this->joint_names[i],
219  _forces[i]
220  );
221  }
222 
223  auto end = std::chrono::steady_clock::now();
224 
225  std::chrono::duration<double,std::micro> diff = end - start;
226 
227  ROS_DEBUG_STREAM("Time spent resetting commands and applying torques: " << diff.count() << " microseconds.");
228 }
229 
230 // Set the a single joints target velocity
231 void SingleLegPlugin::SetJointVelocity(const std::string &_joint_name, const double &_vel)
232 {
233  this->model->GetJointController()->SetVelocityTarget(
234  this->model_name + "::" + _joint_name,
235  _vel
236  );
237 }
238 
239 // Set joint target velocities
240 void SingleLegPlugin::SetJointVelocities(const std::vector<double> &_vel)
241 {
242  auto start = std::chrono::steady_clock::now();
243 
244  if (this->controlMode != 2)
245  {
246  this->model->GetJointController()->Reset();
247 
249  }
250 
251  for (size_t i = 0; i < this->joint_names.size(); i++)
252  {
253  this->model->GetJointController()->SetVelocityTarget(
254  this->model_name + "::" + this->joint_names[i],
255  _vel[i]
256  );
257  }
258 
259  auto end = std::chrono::steady_clock::now();
260 
261  std::chrono::duration<double,std::micro> diff = end - start;
262 
263  ROS_DEBUG_STREAM("Time spent resetting commands and setting velocity targets: " << diff.count() << " microseconds.");
264 }
265 
266 // Set joint target positions
267 void SingleLegPlugin::SetJointPositions(const std::vector<double> &_pos)
268 {
269  auto start = std::chrono::steady_clock::now();
270 
271  if (this->controlMode != 1)
272  {
273  this->model->GetJointController()->Reset();
274 
276  }
277 
278  for (size_t i = 0; i < this->joint_names.size(); i++)
279  {
280  this->model->GetJointController()->SetPositionTarget(
281  this->model_name + "::" + this->joint_names[i],
283  );
284  }
285 
286  auto end = std::chrono::steady_clock::now();
287 
288  std::chrono::duration<double,std::micro> diff = end - start;
289 
290  ROS_DEBUG_STREAM("Time spent resetting commands and setting position targets: " << diff.count() << " microseconds.");
291 }
292 
293 // Callback for ROS Joint State messages
294 void SingleLegPlugin::OnJointStateMsg(const sensor_msgs::JointStateConstPtr &_msg)
295 {
296  if ((!_msg->position.empty()) && (_msg->position.size() == NUMJOINTS))
297  {
298  this->SetJointPositions(_msg->position);
299  }
300 
301  if ((!_msg->velocity.empty()) && (_msg->velocity.size() == NUMJOINTS))
302  {
303  this->SetJointVelocities(_msg->velocity);
304  }
305 
306  if ((!_msg->effort.empty()) && (_msg->effort.size() == NUMJOINTS))
307  {
308  this->SetJointForces(_msg->effort);
309  }
310 }
311 
312 // Callback for ROS Force messages
313 void SingleLegPlugin::OnForceMsg(const std_msgs::Float64MultiArrayConstPtr &_msg)
314 {
315  this->SetJointForces(_msg->data);
316 }
317 
318 // Callback for ROS Velocity messages
319 void SingleLegPlugin::OnVelMsg(const std_msgs::Float64MultiArrayConstPtr &_msg)
320 {
321  this->SetJointVelocities(_msg->data);
322 }
323 
324 // Callback for ROS Position messages
325 void SingleLegPlugin::OnPosMsg(const std_msgs::Float64MultiArrayConstPtr &_msg)
326 {
327  this->SetJointPositions(_msg->data);
328 }
329 
330 // Setup thread to process messages
332 {
333  static const double timeout = 0.000001;
334  while (this->rosNode->ok())
335  {
336  this->rosProcessQueue.callAvailable(ros::WallDuration(timeout));
337  }
338 }
339 
340 // Setup thread to process messages
342 {
343  ros::Rate loop_rate(300);
344  while (this->rosNode->ok())
345  {
346  Eigen::Matrix<double, 9, 1> q; // generalized coordinates
347  Eigen::Matrix<double, 9, 1> u; // generalized velocities
348  Eigen::Matrix<double, 3, 1> tau; // joint forces (torques)
349 
350  q.block(0,0,5,0) << this->GetBasePose();
351  q.block(6,0,8,0) << this->GetJointPositions();
352 
353  u.block(0,0,5,0) << this->GetBaseTwist();
354  u.block(6,0,8,0) << this->GetJointVelocities();
355 
356  tau = this->GetJointForces();
357 
358  std_msgs::Float64MultiArray gen_coord_msg;
359  std_msgs::Float64MultiArray gen_vel_msg;
360  std_msgs::Float64MultiArray joint_forces_msg;
361 
362  tf::matrixEigenToMsg(q, gen_coord_msg);
363  tf::matrixEigenToMsg(u, gen_vel_msg);
364  tf::matrixEigenToMsg(tau, joint_forces_msg);
365 
366  this->genCoordPub.publish(gen_coord_msg);
367  this->genVelPub.publish(gen_vel_msg);
368  this->jointForcesPub.publish(joint_forces_msg);
369 
370  loop_rate.sleep();
371  }
372 }
373 
374 // Initialize ROS
376 {
377  if (!ros::isInitialized())
378  {
379  int argc = 0;
380  char **argv = NULL;
381  ros::init(
382  argc,
383  argv,
384  "gazebo_client",
385  ros::init_options::NoSigintHandler
386  );
387  }
388 
389  this->rosNode.reset(new ros::NodeHandle("gazebo_client"));
390 
391  ros::AdvertiseServiceOptions reset_simulation_aso =
392  ros::AdvertiseServiceOptions::create<std_srvs::Empty>(
393  "/" + this->model->GetName() + "/reset_simulation",
394  boost::bind(&SingleLegPlugin::ResetSimulation, this, _1, _2),
395  ros::VoidPtr(),
396  &this->rosProcessQueue
397  );
398 
399  ros::AdvertiseOptions gen_coord_ao =
400  ros::AdvertiseOptions::create<std_msgs::Float64MultiArray>(
401  "/" + this->model->GetName() + "/gen_coord",
402  1,
403  ros::SubscriberStatusCallback(),
404  ros::SubscriberStatusCallback(),
405  ros::VoidPtr(),
406  &this->rosPublishQueue
407  );
408 
409  ros::AdvertiseOptions gen_vel_ao =
410  ros::AdvertiseOptions::create<std_msgs::Float64MultiArray>(
411  "/" + this->model->GetName() + "/gen_vel",
412  1,
413  ros::SubscriberStatusCallback(),
414  ros::SubscriberStatusCallback(),
415  ros::VoidPtr(),
416  &this->rosPublishQueue
417  );
418 
419  ros::AdvertiseOptions joint_forces_ao =
420  ros::AdvertiseOptions::create<std_msgs::Float64MultiArray>(
421  "/" + this->model->GetName() + "/joint_forces",
422  1,
423  ros::SubscriberStatusCallback(),
424  ros::SubscriberStatusCallback(),
425  ros::VoidPtr(),
426  &this->rosPublishQueue
427  );
428 
429  ros::SubscribeOptions joint_state_so =
430  ros::SubscribeOptions::create<sensor_msgs::JointState>(
431  "/" + this->model->GetName() + "/joint_state_cmd",
432  1,
433  boost::bind(&SingleLegPlugin::OnJointStateMsg, this, _1),
434  ros::VoidPtr(),
435  &this->rosProcessQueue
436  );
437 
438  ros::SubscribeOptions force_so =
439  ros::SubscribeOptions::create<std_msgs::Float64MultiArray>(
440  "/" + this->model->GetName() + "/force_cmd",
441  1,
442  boost::bind(&SingleLegPlugin::OnForceMsg, this, _1),
443  ros::VoidPtr(),
444  &this->rosProcessQueue
445  );
446 
447  ros::SubscribeOptions vel_so =
448  ros::SubscribeOptions::create<std_msgs::Float64MultiArray>(
449  "/" + this->model->GetName() + "/vel_cmd",
450  1,
451  boost::bind(&SingleLegPlugin::OnVelMsg, this, _1),
452  ros::VoidPtr(),
453  &this->rosProcessQueue
454  );
455 
456  ros::SubscribeOptions pos_so =
457  ros::SubscribeOptions::create<std_msgs::Float64MultiArray>(
458  "/" + this->model->GetName() + "/pos_cmd",
459  1,
460  boost::bind(&SingleLegPlugin::OnPosMsg, this, _1),
461  ros::VoidPtr(),
462  &this->rosProcessQueue
463  );
464 
465  this->resetSimService = this->rosNode->advertiseService(reset_simulation_aso);
466 
467  this->genCoordPub = this->rosNode->advertise(gen_coord_ao);
468 
469  this->genVelPub = this->rosNode->advertise(gen_vel_ao);
470 
471  this->jointForcesPub = this->rosNode->advertise(joint_forces_ao);
472 
473  this->jointStateSub = this->rosNode->subscribe(joint_state_so);
474 
475  this->forceSub = this->rosNode->subscribe(force_so);
476 
477  this->velSub = this->rosNode->subscribe(vel_so);
478 
479  this->posSub = this->rosNode->subscribe(pos_so);
480 
481 }
482 
483 // Initialize ROS Publish and Process Queue Threads
485 {
486  this->rosPublishQueueThread = std::thread(
487  std::bind(&SingleLegPlugin::PublishQueueThread, this)
488  );
489 
490  this->rosProcessQueueThread = std::thread(
491  std::bind(&SingleLegPlugin::ProcessQueueThread, this)
492  );
493 }
494 
495 // Load configuration
497 {
498  if (!this->rosNode->getParam("joint_names", this->joint_names))
499  {
500  ROS_ERROR("Could not read joint names from parameter server.");
501  return false;
502  }
503 
504  if (!this->rosNode->getParam("joint_config", this->joint_config))
505  {
506  ROS_ERROR("Could not read joint config from parameter server.");
507  return false;
508  }
509 
510  if (!this->rosNode->getParam("joint_velocity_controller/p_gains", this->vel_p_gains))
511  {
512  ROS_ERROR("Could not read velocity P-gains from parameter server.");
513  return false;
514  }
515 
516  if (!this->rosNode->getParam("joint_velocity_controller/i_gains", this->vel_i_gains))
517  {
518  ROS_ERROR("Could not read velocity I-gains from parameter server.");
519  return false;
520  }
521 
522  if (!this->rosNode->getParam("joint_velocity_controller/d_gains", this->vel_d_gains))
523  {
524  ROS_ERROR("Could not read velocity D-gains from parameter server.");
525  return false;
526  }
527 
528  if (!this->rosNode->getParam("joint_position_controller/p_gains", this->pos_p_gains))
529  {
530  ROS_ERROR("Could not read position P-gains from parameter server.");
531  return false;
532  }
533 
534  if (!this->rosNode->getParam("joint_position_controller/i_gains", this->pos_i_gains))
535  {
536  ROS_ERROR("Could not read position I-gains from parameter server.");
537  return false;
538  }
539 
540  if (!this->rosNode->getParam("joint_position_controller/d_gains", this->pos_d_gains))
541  {
542  ROS_ERROR("Could not read position D-gains from parameter server.");
543  return false;
544  }
545 
546  if (joint_names.size() != vel_p_gains.size() ||
547  joint_names.size() != vel_i_gains.size() ||
548  joint_names.size() != vel_d_gains.size() ||
549  joint_names.size() != pos_p_gains.size() ||
550  joint_names.size() != pos_i_gains.size() ||
551  joint_names.size() != pos_d_gains.size())
552  {
553  ROS_ERROR("Mismatch in number of joints and number of gains.");
554  return false;
555  }
556 
557  return true;
558 }
559 
560 // Initialize Joint Controllers
562 {
563  for (size_t i = 0; i < this->joint_names.size(); i++)
564  {
565  this->model->GetJointController()->SetVelocityPID(
566  this->model_name + "::" + this->joint_names[i],
567  common::PID(vel_p_gains[i], vel_i_gains[i], vel_d_gains[i])
568  );
569 
570  this->model->GetJointController()->SetPositionPID(
571  this->model_name + "::" + this->joint_names[i],
572  common::PID(pos_p_gains[i], pos_i_gains[i], pos_d_gains[i])
573  );
574  }
575 }
576 
577 // Initialize joint configuration
579 {
581 
582  for (size_t i = 0; i < this->joint_names.size(); i++)
583  {
584  // Set default position
585  this->model->GetJointController()->SetJointPosition(
586  this->model_name + "::" + this->joint_names[i],
588  );
589 
590  // Set controller position reference
591  this->model->GetJointController()->SetPositionTarget(
592  this->model_name + "::" + this->joint_names[i],
594  );
595  }
596 
597 }
598 
599 bool SingleLegPlugin::ResetSimulation(const std_srvs::Empty::Request &_req,
600  std_srvs::Empty::Response &_res)
601 {
602  this->world->Reset();
603 
604  this->model->GetJointController()->Reset();
605 
607 
608  for (size_t i = 0; i < this->joint_names.size(); i++)
609  {
610  // Reset Torques
611  this->model->GetJointController()->SetForce(
612  this->model_name + "::" + this->joint_names[i],
613  0
614  );
615 
616  // Set default position
617  this->model->GetJointController()->SetJointPosition(
618  this->model_name + "::" + this->joint_names[i],
620  );
621 
622  // Set controller position reference
623  this->model->GetJointController()->SetPositionTarget(
624  this->model_name + "::" + this->joint_names[i],
626  );
627  }
628 
629  return true;
630 }
631 
632 } // namespace gazebo
void OnForceMsg(const std_msgs::Float64MultiArrayConstPtr &_msg)
The OnRosMsg function handles an incoming force message from ROS.
void ProcessQueueThread()
The ProcessQueueThread function is a ROS helper function that processes messages.
std::thread rosProcessQueueThread
Thread running the rosProcessQueue.
ros::Subscriber posSub
ROS Position Subscriber.
void SetJointPositions(const std::vector< double > &_pos)
Set the position of the joints.
virtual void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
The Load function is called by Gazebo when the plugin is inserted into simulation.
virtual ~SingleLegPlugin()
Destructor.
double GetJointPosition(const std::string &_joint_name)
Get current position at a specific joint.
ros::Subscriber forceSub
ROS Force Subscriber.
Eigen::Matrix< double, 6, 1 > GetBaseTwist()
Get current base twist for the robot.
Eigen::Matrix< double, 6, 1 > GetBasePose()
Get current base pose for the robot.
bool LoadParametersRos()
The LoadParametersRos function is called to load conffloatiguration from the parameter server.
std::vector< double > vel_i_gains
Vector of Velocity I-gains.
double GetJointVelocity(const std::string &_joint_name)
Get current velocity at a specific joint.
std::vector< double > joint_config
Vector of joint configuration.
ros::Publisher genCoordPub
ROS Generalized Coordinates Publisher.
void SetJointForce(const std::string &_joint_name, const double &_force)
Apply force at a specific joint.
void OnJointStateMsg(const sensor_msgs::JointStateConstPtr &_msg)
The OnJointStateMsg function handles an incoming joint state message from ROS.
Eigen::Matrix< double, 3, 1 > GetJointPositions()
Get current joint positions for the robot.
std::string model_name
Model name.
ros::Publisher jointForcesPub
ROS Joint Forces (Torques) Publisher.
void InitRos()
The initRos function is called to initialize ROS.
physics::LinkPtr base
Pointer to the body link.
std::unique_ptr< ros::NodeHandle > rosNode
Node used for ROS transport.
std::vector< double > vel_p_gains
Vector of Velocity P-gains.
std::map< std::string, physics::JointPtr > joints
Pointers to the joints.
void PublishQueueThread()
The PublishQueueThread function is a ROS helper function that publish state messages.
std::vector< double > pos_i_gains
Vector of Position I-gains.
Eigen::Matrix< double, 3, 1 > GetJointVelocities()
Get current joint velocities for the robot.
physics::WorldPtr world
Pointer to the world.
ControlMode controlMode
Control mode indicator { position = 1, velocity = 2, torque = 3 }.
void InitJointConfiguration()
The InitJointConfiguration function is called to initialize the desired joint configuration.
void SetJointForces(const std::vector< double > &_forces)
Apply joint forces.
bool ResetSimulation(const std_srvs::Empty::Request &_req, std_srvs::Empty::Response &_res)
The ResetSimulation function handles an incoming reset simulation service request.
ros::ServiceServer resetSimService
ROS Reset Simulation Service.
void OnPosMsg(const std_msgs::Float64MultiArrayConstPtr &_msg)
The OnRosMsg function handles an incoming velocity message from ROS.
void InitRosQueueThreads()
The InitRosQueueThreads function is called to initialize the ROS Publish and Process Queue Threads.
ros::Subscriber jointStateSub
ROS Joint State Subscriber.
Eigen::Matrix< double, 3, 1 > GetJointForces()
Get current joint forces for the robot.
ros::Publisher genVelPub
ROS Generalized Velocities Publisher.
std::vector< std::string > joint_names
Vector of joint names.
double GetJointForce(const std::string &_joint_name)
Get currently applied force at a specific joint.
void InitJointControllers()
The InitJointControllers function is called to setup joint PID controllers.
ros::CallbackQueue rosPublishQueue
ROS callbackque that helps publish messages.
std::vector< double > vel_d_gains
Vector of Velocity D-gains.
ros::CallbackQueue rosProcessQueue
ROS callbackque that helps process messages.
ros::Subscriber velSub
ROS Velocity Subscriber.
void SetJointVelocity(const std::string &_joint_name, const double &_vel)
Set the velocity of the joint.
std::thread rosPublishQueueThread
Thread running the rosPublishQueue.
std::vector< double > pos_d_gains
Vector of Position D-gains.
physics::ModelPtr model
Pointer to the model.
std::vector< double > pos_p_gains
Vector of Position P-gains.
void SetJointVelocities(const std::vector< double > &_vel)
Set the velocity of the joints.
void OnVelMsg(const std_msgs::Float64MultiArrayConstPtr &_msg)
The OnRosMsg function handles an incoming velocity message from ROS.
Eigen::Vector3d Vector3d
Definition: kinematics.h:49
static constexpr unsigned int NUMJOINTS
Fixed variable for num joints.
double wrapAngleToPi(const double &_rad)
The wrapAngleToPi function wraps an input angle to the interval [-pi, pi).
Definition: angle_utils.cpp:45
double degToRad(const double &_deg)
The degToRad function converts degrees to radians.
Definition: angle_utils.cpp:33