Tetrapod Project
controller.cpp
Go to the documentation of this file.
2 
3 Controller::Controller(int controller_freq) :
4  controller_freq(controller_freq)
5 {
6  this->initROS();
7 }
8 
10 {
11  this->nodeHandle->shutdown();
12 }
13 
15 {
16  ros::Rate rate(5);
17 
18  while(!ready_to_proceed)
19  {
20  ros::spinOnce();
21 
22  rate.sleep();
23  }
24 
25  ready_to_proceed = false;
26 }
27 
29 {
30  bool solved_fl, solved_fr, solved_rl, solved_rr;
31 
32  Eigen::Vector3d single_leg_joint_angles = Eigen::Vector3d::Zero();
33 
34  solved_fl = kinematics.SolveSingleLegInverseKinematics(false, Eigen::Vector3d::Zero(), fl_position_body, single_leg_joint_angles);
35 
36  if (solved_fl)
37  {
38  joint_angle_commands.block<3, 1>(0, 0) = single_leg_joint_angles;
39  }
40 
41  solved_fr = kinematics.SolveSingleLegInverseKinematics(true, Eigen::Vector3d::Zero(), fr_position_body, single_leg_joint_angles);
42 
43  if (solved_fr)
44  {
45  joint_angle_commands.block<3, 1>(3, 0) = single_leg_joint_angles;
46  }
47 
48  solved_rl = kinematics.SolveSingleLegInverseKinematics(true, Eigen::Vector3d::Zero(), rl_position_body, single_leg_joint_angles);
49 
50  if (solved_rl)
51  {
52  joint_angle_commands.block<3, 1>(6, 0) = single_leg_joint_angles;
53  }
54 
55  solved_rr = kinematics.SolveSingleLegInverseKinematics(false, Eigen::Vector3d::Zero(), rr_position_body, single_leg_joint_angles);
56 
57  if (solved_rr)
58  {
59  joint_angle_commands.block<3, 1>(9, 0) = single_leg_joint_angles;
60  }
61 
62  return solved_fl && solved_fr && solved_rl && solved_rr;
63 }
64 
66 {
67  if((joint_angle_commands(2) == 0.0) || (joint_angle_commands(5) == 0.0) || (joint_angle_commands(8) == 0.0) || (joint_angle_commands(11) == 0.0))
68  {
69  ROS_WARN("UpdateVelocityCommands - Could not calculate inverse kinematics because of singular translation jacobian");
70  return false;
71  }
72  Eigen::Matrix<double, 3, 3> J_s_fl = this->kinematics.GetTranslationJacobianInB(Kinematics::LegType::frontLeft, Kinematics::BodyType::foot, joint_angle_commands(0), joint_angle_commands(1), joint_angle_commands(2));
73  Eigen::Matrix<double, 3, 3> J_s_fr = this->kinematics.GetTranslationJacobianInB(Kinematics::LegType::frontRight, Kinematics::BodyType::foot, joint_angle_commands(3), joint_angle_commands(4), joint_angle_commands(5));
74  Eigen::Matrix<double, 3, 3> J_s_rl = this->kinematics.GetTranslationJacobianInB(Kinematics::LegType::rearLeft, Kinematics::BodyType::foot, joint_angle_commands(6), joint_angle_commands(7), joint_angle_commands(8));
75  Eigen::Matrix<double, 3, 3> J_s_rr = this->kinematics.GetTranslationJacobianInB(Kinematics::LegType::rearRight, Kinematics::BodyType::foot, joint_angle_commands(9), joint_angle_commands(10), joint_angle_commands(11));
76 
77  this->joint_velocity_commands.block<3, 1>(0, 0) = J_s_fl.inverse() * this->fl_velocity_body;
78  this->joint_velocity_commands.block<3, 1>(3, 0) = J_s_fr.inverse() * this->fr_velocity_body;
79  this->joint_velocity_commands.block<3, 1>(6, 0) = J_s_rl.inverse() * this->rl_velocity_body;
80  this->joint_velocity_commands.block<3, 1>(9, 0) = J_s_rr.inverse() * this->rr_velocity_body;
81 
82  return true;
83 }
84 
86 {
87  //ROS_INFO("Hy: %f\tHp: %f\tKp: %f", joint_angle_commands(0), joint_angle_commands(1), joint_angle_commands(2));
88  // Check if the position commands are within the joint angle limit constraints
89  if (this->kinematics.ValidateSolution(this->joint_angle_commands) == false)
90  {
91  // If they are violated report the problem and don't send a command to the motors
92  ROS_WARN("Position setpoint violates joint limits. Command canceled.");
93 
94  return false;
95  }
96  else // If the joint angles are valid
97  {
98  // Create a joint state message
99  sensor_msgs::JointState joint_state_msg;
100 
101  // Set the time of the joint state message
102  joint_state_msg.header.stamp = ros::Time::now();
103 
104  // Create a float array for joint angle commands
105  std_msgs::Float64MultiArray position_commands;
106 
107  // Put the joint angle reference vector into the position command message
108  tf::matrixEigenToMsg(this->joint_angle_commands, position_commands);
109 
110  // Add the position commands to the joint state message
111  joint_state_msg.position = position_commands.data;
112 
113  // Publish the message
114  joint_command_publisher.publish(joint_state_msg);
115 
116  return true;
117  }
118 }
119 
121 {
122  //Eigen::Vector3d height_offset(0, 0, -0.25);
123  Eigen::Vector3d height_offset(0, 0, - nominal_base_height);
124 
125  fl_position_body = fl_offset + height_offset;
126 
127  fr_position_body = fr_offset + height_offset;
128 
129  rl_position_body = rl_offset + height_offset;
130 
131  rr_position_body = rr_offset + height_offset;
132 
134 
136 }
137 
138 //ROS related functions
140 {
141  // Check if ROS has been initialized. If false, initialize ROS.
142  if(!ros::isInitialized())
143  {
144  int argc = 0;
145  char **argv = NULL;
146  ros::init
147  (
148  argc,
149  argv,
150  node_name,
151  ros::init_options::NoSigintHandler
152  );
153  }
154 
155  nodeHandle.reset(new ros::NodeHandle(node_name));
156 
157  this->shutdownService = nodeHandle->advertiseService(
158  "/my_robot/controller/shutdown",
160  this
161  );
162 
163  this->readyToProceedService = nodeHandle->advertiseService(
164  "/my_robot/controller/ready_to_proceed",
166  this
167  );
168 
169  // Initialize the ready to move subscriber
170  this->ready_to_proceed_subscriber = nodeHandle->subscribe
171  (
172  "/ready_to_proceed",
173  1,
175  this
176  );
177 
178  this->joint_state_subscriber = nodeHandle->subscribe
179  (
180  "/my_robot/joint_state",
181  1,
183  this
184  );
185 
186  this->twist_command_subscriber = nodeHandle->subscribe
187  (
188  "/twist_command",
189  1,
191  this
192  );
193 
194  this->twist_state_subscriber = nodeHandle->subscribe
195  (
196  "/twist_state",
197  1,
199  this
200  );
201 
202  this->base_pose_state_subscriber = nodeHandle->subscribe
203  (
204  "/my_robot/base_pose",
205  1,
207  this
208  );
209 
210  // Initialize the joint command publisher
211  joint_command_publisher = nodeHandle->advertise<sensor_msgs::JointState>("/" + robot_name + "/joint_state_cmd", 1);
212 
213  // Initialize the joint state logger
214  joint_state_logger = nodeHandle->advertise<sensor_msgs::JointState>("/log/joint_states", 1);
215 
216  // Initialize the joint command logger
217  joint_command_logger = nodeHandle->advertise<sensor_msgs::JointState>("/log/joint_commands", 1);
218 
219  // Initialize the base twist state logger
220  base_twist_state_logger = nodeHandle->advertise<std_msgs::Float64MultiArray>("/log/base_twist_state", 1);
221 
222  // Initialize the base pose state logger
223  base_pose_state_logger = nodeHandle->advertise<std_msgs::Float64MultiArray>("/log/base_pose_state", 1);
224 
225  // Initialize the base twist command logger
226  base_twist_command_logger = nodeHandle->advertise<std_msgs::Float64MultiArray>("/log/base_twist_commands", 1);
227 
228  // Initialize the base pose command logger
229  base_pose_command_logger = nodeHandle->advertise<std_msgs::Float64MultiArray>("/log/base_pose_commands", 1);
230 }
231 
232 void Controller::readyToProceedCallback(const std_msgs::Bool &msg)
233 {
234  ready_to_proceed = msg.data;
235 }
236 
237 void Controller::jointStateCallback(const sensor_msgs::JointStatePtr &msg)
238 {
239  for(int i = 0; i < 12; i++)
240  {
241  // Store the jont angles
242  this->joint_angles(i) = msg->position[i];
243 
244  // Store the joint velocities
245  this->joint_velocities(i) = msg->velocity[i];
246 
247  // Store th joint torques
248  this->joint_torques(i) = msg->effort[i];
249  }
250 
251  this->UpdateFeetPositions();
252 }
253 
254 void Controller::TwistCommandCallback(const geometry_msgs::TwistConstPtr &_msg)
255 {
256  this->lin_vel_x = _msg->linear.x;
257  this->lin_vel_y = _msg->linear.y;
258  this->ang_vel_z = _msg->angular.z;
259 }
260 
261 void Controller::TwistStateCallback(const geometry_msgs::TwistConstPtr &_msg)
262 {
263  this->_lin_vel_x_estimated = _msg->linear.x;
264  this->_lin_vel_y_estimated = _msg->linear.y;
265  this->_ang_vel_z_estimated = _msg->angular.z;
266 
267  this->_lin_vel_z_measured = _msg->linear.z;
268  this->_ang_vel_x_measured = _msg->angular.x;
269  this->_ang_vel_y_measured = _msg->angular.y;
270 }
271 
272 void Controller::BasePoseStateCallback(const std_msgs::Float64MultiArrayConstPtr &msg)
273 {
274  for(int i = 0; i < 6; i++)
275  {
276  this->base_pose_state(i) = msg->data[i];
277  }
278 }
279 
280 void Controller::SetTwistCommand(double lin_vel_cmd_x, double lin_vel_cmd_y, double ang_vel_cmd_z)
281 {
282  this->lin_vel_x = lin_vel_cmd_x;
283  this->lin_vel_y = lin_vel_cmd_y;
284  this->ang_vel_z = ang_vel_cmd_z;
285 }
286 
288 {
289  // Creating a general joint state message
290 
291  sensor_msgs::JointState joint_state_msg;
292 
293  std_msgs::Float64MultiArray joint_state_position;
294  std_msgs::Float64MultiArray joint_state_velocity;
295  std_msgs::Float64MultiArray joint_state_torque;
296 
297  joint_state_msg.header.stamp = ros::Time::now();
298 
299  // Fill in data for the joint state message
300 
301  tf::matrixEigenToMsg(this->joint_angles, joint_state_position);
302  tf::matrixEigenToMsg(this->joint_velocities, joint_state_velocity);
303  tf::matrixEigenToMsg(this->joint_torques, joint_state_torque);
304 
305  joint_state_msg.position = joint_state_position.data;
306  joint_state_msg.velocity = joint_state_velocity.data;
307  joint_state_msg.effort = joint_state_torque.data;
308 
309  // Publish the joint state message
310 
311  this->joint_state_logger.publish(joint_state_msg);
312 
313  // Fill in data for the joint command message
314 
315  tf::matrixEigenToMsg(this->joint_angle_commands, joint_state_position);
316  tf::matrixEigenToMsg(this->joint_velocity_commands, joint_state_velocity);
317  tf::matrixEigenToMsg(this->joint_torque_commands, joint_state_torque);
318 
319  joint_state_msg.position = joint_state_position.data;
320  joint_state_msg.velocity = joint_state_velocity.data;
321  joint_state_msg.effort = joint_state_torque.data;
322 
323  // Publish the joint command message
324 
325  this->joint_command_logger.publish(joint_state_msg);
326 
327  // Create a twist message
328 
329  std_msgs::Float64MultiArray base_twist_state_msg;
330 
331  Eigen::Matrix<double, 6, 1> base_twist_state_data = Eigen::Matrix<double, 6, 1>::Zero();
332 
333  base_twist_state_data(0) = this->_lin_vel_x_estimated;
334  base_twist_state_data(1) = this->_lin_vel_y_estimated;
335  base_twist_state_data(2) = this->_lin_vel_z_measured;
336  base_twist_state_data(3) = this->_ang_vel_x_measured;
337  base_twist_state_data(4) = this->_ang_vel_y_measured;
338  base_twist_state_data(5) = this->_ang_vel_z_estimated;
339 
340  tf::matrixEigenToMsg(base_twist_state_data, base_twist_state_msg);
341 
342  this->base_twist_state_logger.publish(base_twist_state_msg);
343 
344  // Create a twist command message
345 
346  std_msgs::Float64MultiArray base_twist_command_msg;
347 
348  Eigen::Matrix<double, 6, 1> base_twist_command_data = Eigen::Matrix<double, 6, 1>::Zero();
349 
350  base_twist_command_data(0) = this->lin_vel_x;
351  base_twist_command_data(1) = this->lin_vel_y;
352  base_twist_command_data(5) = this->ang_vel_z;
353 
354  tf::matrixEigenToMsg(base_twist_command_data, base_twist_command_msg);
355 
356  this->base_twist_command_logger.publish(base_twist_command_msg);
357 
358  // Create a pose message
359 
360  std_msgs::Float64MultiArray base_pose_msg;
361 
362  tf::matrixEigenToMsg(base_pose_state, base_pose_msg);
363 
364  this->base_pose_state_logger.publish(base_pose_msg);
365 
366  // Create a pose command message
367 
368  std_msgs::Float64MultiArray base_pose_command_msg;
369 
370  tf::matrixEigenToMsg(base_pose_commands, base_pose_command_msg);
371 
372  this->base_pose_command_logger.publish(base_pose_command_msg);
373 
374 }
375 
377 {
379  {
380  ros::Duration(1.0).sleep();
381  ROS_WARN("Waiting for initial states");
382  ros::spinOnce();
383  }
384 }
385 
387 {
388  // Stage 1
389  // We want to move the yaw actuators so that they all face in a direction of +-45 or +-135 degrees
390  // At the same time we want to keep the hip pitch and knee pitch angles equal to zero
391 
392  Eigen::Matrix<double, 12, 1> goal_joint_angles = Eigen::Matrix<double, 12, 1>::Zero();
393  goal_joint_angles(0) = M_PI/4.0;
394  goal_joint_angles(3) = - M_PI/4.0;
395  goal_joint_angles(6) = M_PI*3.0/4.0;
396  goal_joint_angles(9) = - M_PI*3.0/4.0;
397 
398  this->MoveJointsToSetpoints(goal_joint_angles);
399  /*
400  joint_angle_commands(0) = M_PI/4.0;
401  joint_angle_commands(3) = - M_PI/4.0;
402  joint_angle_commands(6) = M_PI*3.0/4.0;
403  joint_angle_commands(9) = - M_PI*3.0/4.0;
404  */
405  /*
406  Eigen::Matrix<double, 3, 1> fl_desired_joint_angles(joint_angles(0), 0.0, 0.0);
407  Eigen::Matrix<double, 3, 1> fr_desired_joint_angles(joint_angles(3), 0.0, 0.0);
408  Eigen::Matrix<double, 3, 1> rl_desired_joint_angles(joint_angles(6), 0.0, 0.0);
409  Eigen::Matrix<double, 3, 1> rr_desired_joint_angles(joint_angles(9), 0.0, 0.0);
410 
411  fl_goal_foot_pos = this->kinematics.SolveSingleLegForwardKinematics(fl_desired_joint_angles);
412  fr_goal_foot_pos = this->kinematics.SolveSingleLegForwardKinematics(fr_desired_joint_angles);
413  rl_goal_foot_pos = this->kinematics.SolveSingleLegForwardKinematics(rl_desired_joint_angles);
414  rr_goal_foot_pos = this->kinematics.SolveSingleLegForwardKinematics(rr_desired_joint_angles);
415  */
416 
417  //this->MoveFeetToPositions(fl_goal_foot_pos, fr_goal_foot_pos, rl_goal_foot_pos, rr_goal_foot_pos);
418 
419  ROS_WARN("RunStandUpSequence - Stage 1 Complete");
420 
421  // Stage 2
422  // We want to move the feet to their nominal xy positions while keeping the height equal to zero
423  Eigen::Matrix<double, 3, 1> fl_goal_foot_pos;
424  Eigen::Matrix<double, 3, 1> fr_goal_foot_pos;
425  Eigen::Matrix<double, 3, 1> rl_goal_foot_pos;
426  Eigen::Matrix<double, 3, 1> rr_goal_foot_pos;
427 
428  double x_nominal = 0.30;
429  double y_nominal = 0.30;
430 
431  fl_goal_foot_pos(0) = x_nominal;
432  fl_goal_foot_pos(1) = x_nominal;
433  fl_goal_foot_pos(2) = 0.0;
434 
435  fr_goal_foot_pos(0) = x_nominal;
436  fr_goal_foot_pos(1) =-x_nominal;
437  fr_goal_foot_pos(2) = 0.0;
438 
439  rr_goal_foot_pos = - fl_goal_foot_pos;
440  rl_goal_foot_pos = - fr_goal_foot_pos;
441 
442  this->MoveFeetToPositions(fl_goal_foot_pos, fr_goal_foot_pos, rl_goal_foot_pos, rr_goal_foot_pos);
443 
444  ROS_WARN("RunStandUpSequence - Stage 2 Complete");
445 
446  // Stage 3
447  // We want to keep the feet at their nominal xy positions while increasing the the height to the nominal height
448  fl_goal_foot_pos(2) = - nominal_base_height;
449  fr_goal_foot_pos(2) = - nominal_base_height;
450  rl_goal_foot_pos(2) = - nominal_base_height;
451  rr_goal_foot_pos(2) = - nominal_base_height;
452 
453  this->MoveFeetToPositions(fl_goal_foot_pos, fr_goal_foot_pos, rl_goal_foot_pos, rr_goal_foot_pos);
454 
455  ROS_WARN("RunStandUpSequence - Stage 3 Complete");
456 
457  // Stage 4
458  // Move each of the feet to the nominal position
459 
460  this->StandStill(0.5);
461 
462  fl_goal_foot_pos(0) = LEG_OFFSET_LENGTH;
463  fl_goal_foot_pos(1) = LEG_OFFSET_LENGTH;
464  fl_goal_foot_pos(2) = - nominal_base_height;
465 
466  this->MoveFootToPosition(Kinematics::LegType::frontLeft, fl_goal_foot_pos);
467 
468  ROS_WARN("RunStandUpSequence - FL moved successfully");
469 
470  this->StandStill(0.5);
471 
472  ROS_WARN("RunStandUpSequence - FL stance completed");
473 
474  rr_goal_foot_pos(0) = - LEG_OFFSET_LENGTH;
475  rr_goal_foot_pos(1) = - LEG_OFFSET_LENGTH;
476  rr_goal_foot_pos(2) = - nominal_base_height;
477 
478  this->MoveFootToPosition(Kinematics::LegType::rearRight, rr_goal_foot_pos);
479 
480  ROS_WARN("RunStandUpSequence - RR moved successfully");
481 
482  this->StandStill(0.5);
483 
484  ROS_WARN("RunStandUpSequence - RR stance completed");
485 
486  fr_goal_foot_pos(0) = LEG_OFFSET_LENGTH;
487  fr_goal_foot_pos(1) = - LEG_OFFSET_LENGTH;
488  fr_goal_foot_pos(2) = - nominal_base_height;
489 
490  this->MoveFootToPosition(Kinematics::LegType::frontRight, fr_goal_foot_pos);
491 
492  ROS_WARN("RunStandUpSequence - FR moved successfully");
493 
494  this->StandStill(0.5);
495 
496  ROS_WARN("RunStandUpSequence - FR stance completed");
497 
498  rl_goal_foot_pos(0) = - LEG_OFFSET_LENGTH;
499  rl_goal_foot_pos(1) = LEG_OFFSET_LENGTH;
500  rl_goal_foot_pos(2) = - nominal_base_height;
501 
502  this->MoveFootToPosition(Kinematics::LegType::rearLeft, rl_goal_foot_pos);
503 
504  ROS_WARN("RunStandUpSequence - RL moved successfully");
505 
506  this->StandStill(0.5);
507 
508  ROS_WARN("RunStandUpSequence - RL stance completed");
509 
510  return true;
511 }
512 
513 bool Controller::MoveFeetToPositions(Eigen::Matrix<double, 3, 1> fl_goal_foot_pos,
514  Eigen::Matrix<double, 3, 1> fr_goal_foot_pos,
515  Eigen::Matrix<double, 3, 1> rl_goal_foot_pos,
516  Eigen::Matrix<double, 3, 1> rr_goal_foot_pos)
517 {
518  Eigen::Matrix<double, 3, 1> fl_initial_foot_pos = fl_position_body;
519 
520  Eigen::Matrix<double, 3, 1> fr_initial_foot_pos = fr_position_body;
521 
522  Eigen::Matrix<double, 3, 1> rl_initial_foot_pos = rl_position_body;
523 
524  Eigen::Matrix<double, 3, 1> rr_initial_foot_pos = rr_position_body;
525  /*
526  Eigen::Matrix<double, 3, 1> fl_goal_foot_pos = feet_goal_pos.block<3, 1>(0, 0);
527 
528  Eigen::Matrix<double, 3, 1> fr_goal_foot_pos = feet_goal_pos.block<3, 1>(3, 0);
529 
530  Eigen::Matrix<double, 3, 1> rl_goal_foot_pos = feet_goal_pos.block<3, 1>(6, 0);
531 
532  Eigen::Matrix<double, 3, 1> rr_goal_foot_pos = feet_goal_pos.block<3, 1>(9, 0);
533  */
534  Eigen::Matrix<double, 3, 1> fl_desired_foot_pos;
535 
536  Eigen::Matrix<double, 3, 1> fr_desired_foot_pos;
537 
538  Eigen::Matrix<double, 3, 1> rl_desired_foot_pos;
539 
540  Eigen::Matrix<double, 3, 1> rr_desired_foot_pos;
541 
542  Eigen::Matrix<double, 3, 1> fl_desired_joint_angles;
543 
544  Eigen::Matrix<double, 3, 1> fr_desired_joint_angles;
545 
546  Eigen::Matrix<double, 3, 1> rl_desired_joint_angles;
547 
548  Eigen::Matrix<double, 3, 1> rr_desired_joint_angles;
549 
550 
551  // Find the largest position error between the start and the end
552  // This is used to select the number of iterations needed for the trajectory
553 
554  double max_error = 0.0;
555 
556  for(int i = 0; i < ACTUATORS_PER_LEG; i++)
557  {
558  double fl_foot_pos_error = abs(fl_initial_foot_pos(i) - fl_goal_foot_pos(i));
559  double fr_foot_pos_error = abs(fr_initial_foot_pos(i) - fr_goal_foot_pos(i));
560  double rl_foot_pos_error = abs(rl_initial_foot_pos(i) - rl_goal_foot_pos(i));
561  double rr_foot_pos_error = abs(rr_initial_foot_pos(i) - rr_goal_foot_pos(i));
562 
563  if(fl_foot_pos_error > max_error)
564  {
565  max_error = fl_foot_pos_error;
566  }
567 
568  if(fr_foot_pos_error > max_error)
569  {
570  max_error = fr_foot_pos_error;
571  }
572 
573  if(rl_foot_pos_error > max_error)
574  {
575  max_error = rl_foot_pos_error;
576  }
577 
578  if(rr_foot_pos_error > max_error)
579  {
580  max_error = rr_foot_pos_error;
581  }
582  }
583 
584  double max_velocity = 0.1; // [m/s]
585 
586  double trajectory_duration = max_error / max_velocity;
587 
588  int number_of_iterations = int(trajectory_duration * controller_freq);
589 
590  // Move
591  //ROS_INFO("Max error: %f", max_error);
592  //ROS_INFO("Iterations: %d", number_of_iterations);
593  ros::Rate publish_rate(controller_freq);
594 
595  /*
596  ROS_INFO("Initial Angles - FL1: %f\tFL2: %f\tFL3: %f\tFR1: %f\tFR2: %f\tFR3: %f\tRL1: %f\tRL2: %f\tRL3: %f\tRR1: %f\tRR2: %f\tRR3: %f",
597  joint_angles(0), joint_angles(1), joint_angles(2), joint_angles(3), joint_angles(4), joint_angles(5),
598  joint_angles(6), joint_angles(7), joint_angles(8), joint_angles(9), joint_angles(10), joint_angles(11));
599  */
600 
601  /*
602  //ROS_INFO("Initial - FL1: %f\tFL2: %f\tFL3: %f\tFR1: %f\tFR2: %f\tFR3: %f\tRL1: %f\tRL2: %f\tRL3: %f\tRR1: %f\tRR2: %f\tRR3: %f",
603  fl_initial_foot_pos(0), fl_initial_foot_pos(1), fl_initial_foot_pos(2),
604  fr_initial_foot_pos(0), fr_initial_foot_pos(1), fr_initial_foot_pos(2),
605  rl_initial_foot_pos(0), rl_initial_foot_pos(1), rl_initial_foot_pos(2),
606  rr_initial_foot_pos(0), rr_initial_foot_pos(1), rr_initial_foot_pos(2));
607  */
608 
609  for(int i = 0; i < number_of_iterations; i++)
610  {
611  ros::spinOnce();
612 
613  // Calculate the desired foot positions
614  fl_desired_foot_pos = fl_initial_foot_pos + double(i)/double(number_of_iterations) * (fl_goal_foot_pos - fl_initial_foot_pos);
615  fr_desired_foot_pos = fr_initial_foot_pos + double(i)/double(number_of_iterations) * (fr_goal_foot_pos - fr_initial_foot_pos);
616  rl_desired_foot_pos = rl_initial_foot_pos + double(i)/double(number_of_iterations) * (rl_goal_foot_pos - rl_initial_foot_pos);
617  rr_desired_foot_pos = rr_initial_foot_pos + double(i)/double(number_of_iterations) * (rr_goal_foot_pos - rr_initial_foot_pos);
618 
619  /*
620  ROS_INFO("Current - FL1: %f\tFL2: %f\tFL3: %f\tFR1: %f\tFR2: %f\tFR3: %f\tRL1: %f\tRL2: %f\tRL3: %f\tRR1: %f\tRR2: %f\tRR3: %f",
621  fl_desired_foot_pos(0), fl_desired_foot_pos(1), fl_desired_foot_pos(2),
622  fr_desired_foot_pos(0), fr_desired_foot_pos(1), fr_desired_foot_pos(2),
623  rl_desired_foot_pos(0), rl_desired_foot_pos(1), rl_desired_foot_pos(2),
624  rr_desired_foot_pos(0), rr_desired_foot_pos(1), rr_desired_foot_pos(2));
625  */
626 
627  // Calculate the inverse joint angles
628  if(this->kinematics.SolveSingleLegInverseKinematics(this->kinematics.GetflOffset(), fl_desired_foot_pos, fl_desired_joint_angles) == false)
629  {
630  ROS_WARN("MoveFeetToPositions - Failed to solve IK for FL");
631  return false;
632  }
633  if(this->kinematics.SolveSingleLegInverseKinematics(this->kinematics.GetfrOffset(), fr_desired_foot_pos, fr_desired_joint_angles) == false)
634  {
635  ROS_WARN("MoveFeetToPositions - Failed to solve IK for FR");
636  return false;
637  }
638  if(this->kinematics.SolveSingleLegInverseKinematics(this->kinematics.GetrlOffset(), rl_desired_foot_pos, rl_desired_joint_angles) == false)
639  {
640  ROS_WARN("MoveFeetToPositions - Failed to solve IK for RL");
641  return false;
642  }
643  if(this->kinematics.SolveSingleLegInverseKinematics(this->kinematics.GetrrOffset(), rr_desired_foot_pos, rr_desired_joint_angles) == false)
644  {
645  ROS_WARN("MoveFeetToPositions - Failed to solve IK for RR");
646  return false;
647  }
648 
649  this->joint_angle_commands.block<3, 1>(0, 0) = fl_desired_joint_angles;
650  this->joint_angle_commands.block<3, 1>(3, 0) = fr_desired_joint_angles;
651  this->joint_angle_commands.block<3, 1>(6, 0) = rl_desired_joint_angles;
652  this->joint_angle_commands.block<3, 1>(9, 0) = rr_desired_joint_angles;
653 
654  /*
655  ROS_INFO("Angle commands - FL1: %f\tFL2: %f\tFL3: %f\tFR1: %f\tFR2: %f\tFR3: %f\tRL1: %f\tRL2: %f\tRL3: %f\tRR1: %f\tRR2: %f\tRR3: %f",
656  joint_angle_commands(0), joint_angle_commands(1), joint_angle_commands(2), joint_angle_commands(3), joint_angle_commands(4), joint_angle_commands(5),
657  joint_angle_commands(6), joint_angle_commands(7), joint_angle_commands(8), joint_angle_commands(9), joint_angle_commands(10), joint_angle_commands(11));
658  */
659 
661  this->WriteToLog();
662  publish_rate.sleep();
663  }
664 
665  return true;
666 }
667 
668 bool Controller::MoveJointsToSetpoints(Eigen::Matrix<double, 12, 1> goal_joint_angles)
669 {
670  if(this->kinematics.ValidateSolution(goal_joint_angles) == false)
671  {
672  ROS_WARN("MoveJointToSetpoints - Invalid goal joint positions");
673  return false;
674  }
675 
676  Eigen::Matrix<double, 12, 1> initial_joint_angles = this->joint_angles;
677 
678  double max_error = 0.0;
679 
680  for(int i = 0; i < 12; i++)
681  {
682  double error = abs(initial_joint_angles(i) - goal_joint_angles(i));
683 
684  if(error > max_error)
685  {
686  max_error = error;
687  }
688  }
689 
690  double max_angle_rate = 0.3;
691 
692  double trajectory_duration = max_error / max_angle_rate;
693 
694  int number_of_iterations = int(trajectory_duration * controller_freq);
695 
696  ros::Rate publish_rate(controller_freq);
697 
698  for(int i = 0; i < number_of_iterations; i++)
699  {
700  ros::spinOnce();
701 
702  joint_angle_commands = initial_joint_angles + double(i)/double(number_of_iterations) * (goal_joint_angles - initial_joint_angles);
703 
705  this->WriteToLog();
706  publish_rate.sleep();
707  }
708 
709  return true;
710 }
711 
713 {
714  fl_position_body = kinematics.SolveSingleLegHipToFootForwardKinematics(Kinematics::LegType::frontLeft, joint_angles.block<3, 1>(0, 0));
715  fr_position_body = kinematics.SolveSingleLegHipToFootForwardKinematics(Kinematics::LegType::frontRight, joint_angles.block<3, 1>(3, 0));
716  rl_position_body = kinematics.SolveSingleLegHipToFootForwardKinematics(Kinematics::LegType::rearLeft, joint_angles.block<3, 1>(6, 0));
717  rr_position_body = kinematics.SolveSingleLegHipToFootForwardKinematics(Kinematics::LegType::rearRight, joint_angles.block<3, 1>(9, 0));
718 }
719 
720 bool Controller::MoveFootToPosition(const Kinematics::LegType &leg_type, const Eigen::Matrix<double, 3, 1> &goal_foot_position)
721 {
722  Eigen::Matrix<double, 3, 1> initial_foot_position;
723 
724  bool leg_offset;
725 
726  int joint_index_start;
727 
728  switch (leg_type)
729  {
730  case Kinematics::LegType::frontLeft:
731  {
732  ROS_WARN("MoveFootToPosition - FL");
733  initial_foot_position = this->fl_position_body;
734  leg_offset = this->kinematics.GetflOffset();
735  joint_index_start = 0;
736  break;
737  }
738  case Kinematics::LegType::frontRight:
739  {
740  initial_foot_position = this->fr_position_body;
741  leg_offset = this->kinematics.GetfrOffset();
742  joint_index_start = 3;
743  break;
744  }
745  case Kinematics::LegType::rearLeft:
746  {
747  initial_foot_position = this->rl_position_body;
748  leg_offset = this->kinematics.GetrlOffset();
749  joint_index_start = 6;
750  break;
751  }
752  case Kinematics::LegType::rearRight:
753  {
754  initial_foot_position = this->rr_position_body;
755  leg_offset = this->kinematics.GetrrOffset();
756  joint_index_start = 9;
757  break;
758  }
759  default:
760  ROS_WARN("MoveFootToPosition - Invalid leg chosen");
761  return false;
762  break;
763  }
764 
765  // Can add check to see if the target foot position is feasible
766 
767  double swing_period = 0.3;
768 
769  double step_height = 0.1;
770 
771  int number_of_iterations = int(swing_period * controller_freq);
772 
773  int half_number_of_iterations = number_of_iterations/2;
774 
775  number_of_iterations = half_number_of_iterations * 2; // This is to ensure that we have a parallel number of iterations
776 
777  Eigen::Matrix<double, 3, 1> desired_foot_position;
778 
779  Eigen::Matrix<double, 3, 1> desired_joint_angles;
780 
781  ros::Rate publish_rate(controller_freq);
782 
783  for(int i = 0; i <= number_of_iterations; i++)
784  {
785  ros::spinOnce();
786 
787  //ROS_INFO("Iteration: %d\tN: %d", i, number_of_iterations);
788  desired_foot_position = initial_foot_position + double(i)/double(number_of_iterations) * (goal_foot_position - initial_foot_position);
789 
790  if(i <= half_number_of_iterations)
791  {
792  desired_foot_position(2) = - nominal_base_height + step_height * double(i)/double(half_number_of_iterations);
793  }
794  else
795  {
796  desired_foot_position(2) = - nominal_base_height + step_height * (1.0 - double(i - half_number_of_iterations)/double(half_number_of_iterations));
797  }
798 
799  if(this->kinematics.SolveSingleLegInverseKinematics(leg_offset, desired_foot_position, desired_joint_angles) == false)
800  {
801  ROS_WARN("MoveFootToPosition - Failed to solve IK");
802 
803 
804 
805  return false;
806  }
807  else
808  {
809  joint_angle_commands.block<3, 1>(joint_index_start, 0) = desired_joint_angles;
810 
811  //ROS_INFO("FL joint angles - hy: %f\thp: %f\tkp: %f", joint_angle_commands(0), joint_angle_commands(1), joint_angle_commands(2));
812 
814 
815  this->WriteToLog();
816 
817  publish_rate.sleep();
818  }
819  }
820 
821  return true;
822 }
823 
824 void Controller::StandStill(const double &duration)
825 {
826  ros::Rate control_rate(controller_freq);
827 
828  int number_of_iterations = duration * controller_freq;
829 
830  for(int i = 0; i < number_of_iterations; i++)
831  {
832  ros::spinOnce();
833 
835 
836  this->WriteToLog();
837 
838  control_rate.sleep();
839  }
840 }
841 
842 bool Controller::ReadyToProceed(std_srvs::Empty::Request &_req,
843  std_srvs::Empty::Response &_res)
844 {
845  this->ready_to_proceed = true;
846 
847  return true;
848 }
849 
850 bool Controller::Shutdown(std_srvs::Empty::Request &_req,
851  std_srvs::Empty::Response &_res)
852 {
853  this->nodeHandle->shutdown();
854 
855  return true;
856 }
Eigen::Vector3d fr_offset
Definition: controller.h:137
bool UpdateJointCommands()
Definition: controller.cpp:28
ros::NodeHandlePtr nodeHandle
Definition: controller.h:114
void TwistCommandCallback(const geometry_msgs::TwistConstPtr &_msg)
Converts twist command messages into desired linear and angular body velocities.
Definition: controller.cpp:254
virtual ~Controller()
Definition: controller.cpp:9
bool ready_to_proceed
Definition: controller.h:104
double _ang_vel_x_measured
Definition: controller.h:202
double _lin_vel_x_estimated
Definition: controller.h:194
void jointStateCallback(const sensor_msgs::JointStatePtr &msg)
Definition: controller.cpp:237
double _lin_vel_y_estimated
Definition: controller.h:196
Eigen::Vector3d fl_offset
Definition: controller.h:135
double lin_vel_y
The desired linear robot velocity in the body frame's y direction.
Definition: controller.h:189
JointState joint_angles
Definition: controller.h:175
ros::Publisher joint_state_logger
Definition: controller.h:212
Eigen::Vector3d fl_velocity_body
Definition: controller.h:151
ros::Subscriber ready_to_proceed_subscriber
Definition: controller.h:128
void BasePoseStateCallback(const std_msgs::Float64MultiArrayConstPtr &msg)
Definition: controller.cpp:272
Eigen::Vector3d rr_offset
Definition: controller.h:141
bool UpdateVelocityCommands()
Definition: controller.cpp:65
ros::Publisher base_twist_state_logger
Definition: controller.h:216
Eigen::Vector3d rl_position_body
Definition: controller.h:147
ros::Subscriber twist_command_subscriber
Subscribes to twist command messages from an external controller.
Definition: controller.h:131
double _ang_vel_y_measured
Definition: controller.h:204
ros::Subscriber base_pose_state_subscriber
Definition: controller.h:126
ros::Publisher joint_command_publisher
Definition: controller.h:122
void StandStill(const double &duration)
Definition: controller.cpp:824
Controller(int controller_freq)
Definition: controller.cpp:3
bool ReadyToProceed(std_srvs::Empty::Request &_req, std_srvs::Empty::Response &_res)
The ReadyToProceed function handles an incoming readyToProceed service request.
Definition: controller.cpp:842
JointState joint_velocity_commands
Definition: controller.h:169
void WaitForInitialState()
Definition: controller.cpp:376
void readyToProceedCallback(const std_msgs::Bool &msg)
Definition: controller.cpp:232
Eigen::Matrix< double, 6, 1 > base_pose_commands
Definition: controller.h:183
Kinematics kinematics
Definition: controller.h:112
Eigen::Vector3d fl_position_body
Definition: controller.h:143
void TwistStateCallback(const geometry_msgs::TwistConstPtr &_msg)
Definition: controller.cpp:261
double _ang_vel_z_estimated
Definition: controller.h:198
int controller_freq
Definition: controller.h:110
Eigen::Vector3d rr_position_body
Definition: controller.h:149
double ang_vel_z
The desired angular robot velocity around the robot's z axis.
Definition: controller.h:192
Eigen::Matrix< double, 6, 1 > base_pose_state
Definition: controller.h:181
ros::Subscriber twist_state_subscriber
Definition: controller.h:133
void UpdateFeetPositions()
Definition: controller.cpp:712
ros::Publisher joint_command_logger
Definition: controller.h:214
JointState joint_torques
Definition: controller.h:179
Eigen::Vector3d fr_position_body
Definition: controller.h:145
std::string robot_name
Definition: controller.h:108
bool MoveFootToPosition(const Kinematics::LegType &leg_type, const Eigen::Matrix< double, 3, 1 > &goal_foot_position)
Definition: controller.cpp:720
void WriteToLog()
Definition: controller.cpp:287
bool Shutdown(std_srvs::Empty::Request &_req, std_srvs::Empty::Response &_res)
The Shutdown function handles an incoming shutdown service request.
Definition: controller.cpp:850
std::string node_name
Definition: controller.h:106
bool MoveFeetToPositions(Eigen::Matrix< double, 3, 1 > fl_goal_foot_pos, Eigen::Matrix< double, 3, 1 > fr_goal_foot_pos, Eigen::Matrix< double, 3, 1 > rl_goal_foot_pos, Eigen::Matrix< double, 3, 1 > rr_goal_foot_pos)
Definition: controller.cpp:513
ros::Publisher base_twist_command_logger
Definition: controller.h:220
double lin_vel_x
The desired linear robot velocity in the body frame's x direction.
Definition: controller.h:186
ros::Publisher base_pose_state_logger
Definition: controller.h:218
Eigen::Vector3d rr_velocity_body
Definition: controller.h:157
Eigen::Vector3d rl_offset
Definition: controller.h:139
void waitForReadyToProceed()
Definition: controller.cpp:14
ros::Subscriber joint_state_subscriber
Definition: controller.h:124
ros::ServiceServer shutdownService
ROS Shutdown Service.
Definition: controller.h:117
ros::ServiceServer readyToProceedService
ROS Ready to Proceed Service.
Definition: controller.h:120
JointState joint_torque_commands
Definition: controller.h:173
JointState joint_angle_commands
Definition: controller.h:167
void initROS()
Definition: controller.cpp:139
Eigen::Vector3d rl_velocity_body
Definition: controller.h:155
void SetTwistCommand(double lin_vel_cmd_x, double lin_vel_cmd_y, double ang_vel_cmd_z)
Definition: controller.cpp:280
double _lin_vel_z_measured
Definition: controller.h:200
double nominal_base_height
Definition: controller.h:206
bool RunStandUpSequence()
Definition: controller.cpp:386
bool sendJointPositionCommands()
Definition: controller.cpp:85
JointState joint_velocities
Definition: controller.h:177
bool MoveJointsToSetpoints(Eigen::Matrix< double, 12, 1 > goal_joint_angles)
Definition: controller.cpp:668
virtual void setInitialConfiguration()
Definition: controller.cpp:120
ros::Publisher base_pose_command_logger
Definition: controller.h:222
Eigen::Vector3d fr_velocity_body
Definition: controller.h:153
bool ValidateSolution(const JointSpaceVector &_q_r)
The ValidateSolution function evaluates whether a set of joint angles is within joint limits.
bool GetrlOffset()
Definition: kinematics.h:668
Vector3d SolveSingleLegHipToFootForwardKinematics(const LegType &_leg_type, const Vector3d &_joint_angles)
The SolveSingleLegHipToFootForwardKinematics function calculates the foot position in the hip frame.
Definition: kinematics.cpp:262
bool GetfrOffset()
Definition: kinematics.h:666
Eigen::Matrix< double, 3, 3 > GetTranslationJacobianInB(const LegType &_leg, const BodyType &_body, const double &_theta_hy, const double &_theta_hp, const double &_theta_kp)
The GetTranslationJacobianInB function returns the 3x3 Jacobian matrix for body linear velocities in ...
Definition: kinematics.cpp:723
bool GetrrOffset()
Definition: kinematics.h:670
bool GetflOffset()
Definition: kinematics.h:664
bool SolveSingleLegInverseKinematics(const bool &_offset, const Vector3d &_h_pos, const Vector3d &_f_pos, Vector3d &_joint_angles)
The SolveSingeLegInverseKinematics function calculates the inverse kinematics for a single leg.
Definition: kinematics.cpp:296
LegType
Leg type enumerator.
Definition: kinematics.h:56
#define ACTUATORS_PER_LEG
Definition: controller.h:27
#define LEG_OFFSET_LENGTH
Definition: controller.h:25
#define UNINITIALIZED_JOINT_STATE
Definition: controller.h:23
Eigen::Vector3d Vector3d
Definition: kinematics.h:49