op3_walking_module.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright 2017 ROBOTIS CO., LTD.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16 
17 /* Author: Kayman */
18 
20 
21 namespace robotis_op
22 {
23 
25  : control_cycle_msec_(8),
26  DEBUG(false)
27 {
28  enable_ = false;
29  module_name_ = "walking_module";
31 
32  init_pose_count_ = 0;
35 
37 
38  // result
39  result_["r_hip_yaw"] = new robotis_framework::DynamixelState();
40  result_["r_hip_roll"] = new robotis_framework::DynamixelState();
41  result_["r_hip_pitch"] = new robotis_framework::DynamixelState();
43  result_["r_ank_pitch"] = new robotis_framework::DynamixelState();
44  result_["r_ank_roll"] = new robotis_framework::DynamixelState();
45 
46  result_["l_hip_yaw"] = new robotis_framework::DynamixelState();
47  result_["l_hip_roll"] = new robotis_framework::DynamixelState();
48  result_["l_hip_pitch"] = new robotis_framework::DynamixelState();
50  result_["l_ank_pitch"] = new robotis_framework::DynamixelState();
51  result_["l_ank_roll"] = new robotis_framework::DynamixelState();
52 
53  result_["r_sho_pitch"] = new robotis_framework::DynamixelState();
54  result_["l_sho_pitch"] = new robotis_framework::DynamixelState();
55 
56  // joint table
57  joint_table_["r_hip_yaw"] = 0;
58  joint_table_["r_hip_roll"] = 1;
59  joint_table_["r_hip_pitch"] = 2;
60  joint_table_["r_knee"] = 3;
61  joint_table_["r_ank_pitch"] = 4;
62  joint_table_["r_ank_roll"] = 5;
63 
64  joint_table_["l_hip_yaw"] = 6;
65  joint_table_["l_hip_roll"] = 7;
66  joint_table_["l_hip_pitch"] = 8;
67  joint_table_["l_knee"] = 9;
68  joint_table_["l_ank_pitch"] = 10;
69  joint_table_["l_ank_roll"] = 11;
70 
71  joint_table_["r_sho_pitch"] = 12;
72  joint_table_["l_sho_pitch"] = 13;
73 
74  target_position_ = Eigen::MatrixXd::Zero(1, result_.size());
75  goal_position_ = Eigen::MatrixXd::Zero(1, result_.size());
76  init_position_ = Eigen::MatrixXd::Zero(1, result_.size());
77  joint_axis_direction_ = Eigen::MatrixXi::Zero(1, result_.size());
78 }
79 
81 {
82  queue_thread_.join();
83 }
84 
85 void WalkingModule::initialize(const int control_cycle_msec, robotis_framework::Robot *robot)
86 {
87  queue_thread_ = boost::thread(boost::bind(&WalkingModule::queueThread, this));
88  control_cycle_msec_ = control_cycle_msec;
89 
90  // m, s, rad
91  // init pose
92  walking_param_.init_x_offset = -0.010;
93  walking_param_.init_y_offset = 0.005;
94  walking_param_.init_z_offset = 0.020;
95  walking_param_.init_roll_offset = 0.0;
96  walking_param_.init_pitch_offset = 0.0 * DEGREE2RADIAN;
97  walking_param_.init_yaw_offset = 0.0 * DEGREE2RADIAN;
98  walking_param_.hip_pitch_offset = 13.0 * DEGREE2RADIAN;
99  // time
100  walking_param_.period_time = 600 * 0.001;
101  walking_param_.dsp_ratio = 0.1;
102  walking_param_.step_fb_ratio = 0.28;
103  // walking
104  walking_param_.x_move_amplitude = 0.0;
105  walking_param_.y_move_amplitude = 0.0;
106  walking_param_.z_move_amplitude = 0.040; // foot height
107  walking_param_.angle_move_amplitude = 0.0;
108  // balance
109  walking_param_.balance_enable = false;
110  walking_param_.balance_hip_roll_gain = 0.5;
111  walking_param_.balance_knee_gain = 0.3;
112  walking_param_.balance_ankle_roll_gain = 1.0;
113  walking_param_.balance_ankle_pitch_gain = 0.9;
114  walking_param_.y_swap_amplitude = 0.020;
115  walking_param_.z_swap_amplitude = 0.005;
116  walking_param_.pelvis_offset = 3.0 * DEGREE2RADIAN;
117  walking_param_.arm_swing_gain = 1.5;
118 
119  // member variable
120  body_swing_y = 0;
121  body_swing_z = 0;
122 
123  x_swap_phase_shift_ = M_PI;
125  x_move_phase_shift_ = M_PI / 2;
129  y_move_phase_shift_ = M_PI / 2;
130  z_swap_phase_shift_ = M_PI * 3 / 2;
131  z_move_phase_shift_ = M_PI / 2;
132  a_move_phase_shift_ = M_PI / 2;
133 
134  ctrl_running_ = false;
135  real_running_ = false;
136  time_ = 0;
137 
138  // R_HIP_YAW, R_HIP_ROLL, R_HIP_PITCH, R_KNEE, R_ANKLE_PITCH, R_ANKLE_ROLL,
139  // L_HIP_YAW, L_HIP_ROLL, L_HIP_PITCH, L_KNEE, L_ANKLE_PITCH, L_ANKLE_ROLL,
140  // R_ARM_SWING, L_ARM_SWING
141  joint_axis_direction_ << -1, -1, -1, -1, 1, 1,
142  -1, -1, 1, 1, -1, 1,
143  1, -1;
144  init_position_ << 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
145  0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
146  5.0, -5.0;
148 
149  ros::NodeHandle ros_node;
150 
151  std::string default_param_path = ros::package::getPath("op3_walking_module") + "/config/param.yaml";
152  ros_node.param<std::string>("walking_param_path", param_path_, default_param_path);
153 
154  loadWalkingParam(param_path_);
155 
156  updateTimeParam();
158 }
159 
161 {
162  ros::NodeHandle ros_node;
163  ros::CallbackQueue callback_queue;
164 
165  ros_node.setCallbackQueue(&callback_queue);
166 
167  /* publish topics */
168  status_msg_pub_ = ros_node.advertise<robotis_controller_msgs::StatusMsg>("robotis/status", 1);
169 
170  /* ROS Service Callback Functions */
171  ros::ServiceServer get_walking_param_server = ros_node.advertiseService("/robotis/walking/get_params",
173  this);
174 
175  /* sensor topic subscribe */
176  ros::Subscriber walking_command_sub = ros_node.subscribe("/robotis/walking/command", 0,
178  ros::Subscriber walking_param_sub = ros_node.subscribe("/robotis/walking/set_params", 0,
180 
181  ros::WallDuration duration(control_cycle_msec_ / 1000.0);
182  while(ros_node.ok())
183  callback_queue.callAvailable(duration);
184 }
185 
186 void WalkingModule::publishStatusMsg(unsigned int type, std::string msg)
187 {
188  robotis_controller_msgs::StatusMsg status_msg;
189  status_msg.header.stamp = ros::Time::now();
190  status_msg.type = type;
191  status_msg.module_name = "Walking";
192  status_msg.status_msg = msg;
193 
194  status_msg_pub_.publish(status_msg);
195 }
196 
197 void WalkingModule::walkingCommandCallback(const std_msgs::String::ConstPtr &msg)
198 {
199  if(enable_ == false)
200  {
201  ROS_WARN("walking module is not ready.");
202  return;
203  }
204 
205  if (msg->data == "start")
206  startWalking();
207  else if (msg->data == "stop")
208  stop();
209  else if (msg->data == "balance on")
210  walking_param_.balance_enable = true;
211  else if (msg->data == "balance off")
212  walking_param_.balance_enable = false;
213  else if (msg->data == "save")
215 }
216 
217 void WalkingModule::walkingParameterCallback(const op3_walking_module_msgs::WalkingParam::ConstPtr &msg)
218 {
219  walking_param_ = *msg;
220 }
221 
222 bool WalkingModule::getWalkigParameterCallback(op3_walking_module_msgs::GetWalkingParam::Request &req,
223  op3_walking_module_msgs::GetWalkingParam::Response &res)
224 {
225  res.parameters = walking_param_;
226 
227  return true;
228 }
229 
230 double WalkingModule::wSin(double time, double period, double period_shift, double mag, double mag_shift)
231 {
232  return mag * sin(2 * M_PI / period * time - period_shift) + mag_shift;
233 }
234 
235 // m, rad
236 // for default op3: it was used from previos version(OP2) but it's not using now.
237 bool WalkingModule::computeIK(double *out, double pos_x, double pos_y, double pos_z, double ori_roll, double ori_pitch,
238  double ori_yaw)
239 {
240  double thigh_length = 93.0 * 0.001; //m
241  double calf_length = 93.0 * 0.001; //m
242  double ankle_length = 33.5 * 0.001; //m
243  double leg_length = 219.5 * 0.001; //m (THIGH_LENGTH + CALF_LENGTH + ANKLE_LENGTH)
244 
245  Eigen::MatrixXd transformation_ad, transformation_da, transformation_cd, transformation_dc, transformation_ac;
246  Eigen::Vector3d vector;
247  double r_ac, acos_value, atan_value, value_k, value_l, value_m, value_n, value_s, value_c, theta;
248 
249  // make transform matrix
250  transformation_ad = robotis_framework::getTransformationXYZRPY(pos_x, pos_y, pos_z, ori_roll, ori_pitch, ori_yaw);
251 
252  vector << pos_x + transformation_ad.coeff(0, 2) * ankle_length, pos_y + transformation_ad.coeff(1, 2) * ankle_length, (pos_z
253  - leg_length) + transformation_ad.coeff(2, 2) * ankle_length;
254 
255  // Get Knee
256  r_ac = vector.norm();
257  acos_value = acos(
258  (r_ac * r_ac - thigh_length * thigh_length - calf_length * calf_length) / (2 * thigh_length * calf_length));
259  if (std::isnan(acos_value) == 1)
260  return false;
261  *(out + 3) = acos_value;
262 
263  // Get Ankle Roll
264  transformation_da = robotis_framework::getInverseTransformation(transformation_ad);
265  double tda_y = transformation_da.coeff(1, 3);
266  double tda_z = transformation_da.coeff(2, 3);
267  value_k = sqrt(tda_y * tda_y + tda_z * tda_z);
268  value_l = sqrt(tda_y * tda_y + (tda_z - ankle_length) * (tda_z - ankle_length));
269  value_m = (value_k * value_k - value_l * value_l - ankle_length * ankle_length) / (2 * value_l * ankle_length);
270  if (value_m > 1.0)
271  value_m = 1.0;
272  else if (value_m < -1.0)
273  value_m = -1.0;
274  acos_value = acos(value_m);
275  if (std::isnan(acos_value) == 1)
276  return false;
277  if (tda_y < 0.0)
278  *(out + 5) = -acos_value;
279  else
280  *(out + 5) = acos_value;
281 
282  // Get Hip Yaw
283  transformation_cd = robotis_framework::getTransformationXYZRPY(0.0, 0.0, -ankle_length, *(out + 5), 0.0, 0.0);
284  transformation_dc = robotis_framework::getInverseTransformation(transformation_cd);
285  transformation_ac = transformation_ad * transformation_dc;
286  atan_value = atan2(-transformation_ac.coeff(0, 1), transformation_ac.coeff(1, 1));
287  if (std::isinf(atan_value) == 1)
288  return false;
289  *(out) = atan_value;
290 
291  // Get Hip Roll
292  atan_value = atan2(transformation_ac.coeff(2, 1),
293  -transformation_ac.coeff(0, 1) * sin(*(out)) + transformation_ac.coeff(1, 1) * cos(*(out)));
294  if (std::isinf(atan_value) == 1)
295  return false;
296  *(out + 1) = atan_value;
297 
298  // Get Hip Pitch and Ankle Pitch
299  atan_value = atan2(transformation_ac.coeff(0, 2) * cos(*(out)) + transformation_ac.coeff(1, 2) * sin(*(out)),
300  transformation_ac.coeff(0, 0) * cos(*(out)) + transformation_ac.coeff(1, 0) * sin(*(out)));
301  if (std::isinf(atan_value) == 1)
302  return false;
303  theta = atan_value;
304  value_k = sin(*(out + 3)) * calf_length;
305  value_l = -thigh_length - cos(*(out + 3)) * calf_length;
306  value_m = cos(*(out)) * vector.x() + sin(*(out)) * vector.y();
307  value_n = cos(*(out + 1)) * vector.z() + sin(*(out)) * sin(*(out + 1)) * vector.x()
308  - cos(*(out)) * sin(*(out + 1)) * vector.y();
309  value_s = (value_k * value_n + value_l * value_m) / (value_k * value_k + value_l * value_l);
310  value_c = (value_n - value_k * value_s) / value_l;
311  atan_value = atan2(value_s, value_c);
312  if (std::isinf(atan_value) == 1)
313  return false;
314  *(out + 2) = atan_value;
315  *(out + 4) = theta - *(out + 3) - *(out + 2);
316 
317  return true;
318 }
319 
321 {
322  period_time_ = walking_param_.period_time; // * 1000; // s -> ms
323  dsp_ratio_ = walking_param_.dsp_ratio;
324  ssp_ratio_ = 1 - dsp_ratio_;
325 
331  z_move_period_time_ = period_time_ * ssp_ratio_ / 2;
333 
339 
343 
344  pelvis_offset_ = walking_param_.pelvis_offset;
345  pelvis_swing_ = pelvis_offset_ * 0.35;
346  arm_swing_gain_ = walking_param_.arm_swing_gain;
347 }
348 
350 {
351  // Forward/Back
352  x_move_amplitude_ = walking_param_.x_move_amplitude;
353  x_swap_amplitude_ = walking_param_.x_move_amplitude * walking_param_.step_fb_ratio;
354 
356  {
357  x_move_amplitude_ *= 0.5;
358  x_swap_amplitude_ *= 0.5;
359  }
360 
361  // Right/Left
362  y_move_amplitude_ = walking_param_.y_move_amplitude / 2;
363  if (y_move_amplitude_ > 0)
365  else
367  y_swap_amplitude_ = walking_param_.y_swap_amplitude + y_move_amplitude_shift_ * 0.04;
368 
369  z_move_amplitude_ = walking_param_.z_move_amplitude / 2;
371  z_swap_amplitude_ = walking_param_.z_swap_amplitude;
373 
374  // Direction
375  if (walking_param_.move_aim_on == false)
376  {
377  a_move_amplitude_ = walking_param_.angle_move_amplitude / 2;
378  if (a_move_amplitude_ > 0)
380  else
382  }
383  else
384  {
385  a_move_amplitude_ = -walking_param_.angle_move_amplitude / 2;
386  if (a_move_amplitude_ > 0)
388  else
390  }
391 }
392 
394 {
395  x_offset_ = walking_param_.init_x_offset;
396  y_offset_ = walking_param_.init_y_offset;
397  z_offset_ = walking_param_.init_z_offset;
398  r_offset_ = walking_param_.init_roll_offset;
399  p_offset_ = walking_param_.init_pitch_offset;
400  a_offset_ = walking_param_.init_yaw_offset;
401  hit_pitch_offset_ = walking_param_.hip_pitch_offset;
402 }
403 
405 {
406  ctrl_running_ = true;
407  real_running_ = true;
408 
409  publishStatusMsg(robotis_controller_msgs::StatusMsg::STATUS_INFO, "Start walking");
410 }
411 
413 {
414  ctrl_running_ = false;
415  publishStatusMsg(robotis_controller_msgs::StatusMsg::STATUS_INFO, "Stop walking");
416 }
417 
419 {
421 }
422 
423 // default [angle : radian, length : m]
424 void WalkingModule::process(std::map<std::string, robotis_framework::Dynamixel *> dxls,
425  std::map<std::string, double> sensors)
426 {
427  if (enable_ == false)
428  return;
429 
430  const double time_unit = control_cycle_msec_ * 0.001; // ms -> s
431  int joint_size = result_.size();
432  double angle[joint_size];
433  double balance_angle[joint_size];
434 
436  {
437  int total_count = calc_joint_tra_.rows();
438  for (int id = 1; id <= result_.size(); id++)
439  target_position_.coeffRef(0, id) = calc_joint_tra_(init_pose_count_, id);
440 
441  init_pose_count_ += 1;
442  if (init_pose_count_ >= total_count)
443  {
445  if (DEBUG)
446  std::cout << "End moving to Init : " << init_pose_count_ << std::endl;
447  }
448 
449  }
451  {
452  // present angle
453  for (std::map<std::string, robotis_framework::DynamixelState *>::iterator state_iter = result_.begin();
454  state_iter != result_.end(); state_iter++)
455  {
456  std::string _joint_name = state_iter->first;
457  int joint_index = joint_table_[_joint_name];
458 
459  robotis_framework::Dynamixel *dxl = NULL;
460  std::map<std::string, robotis_framework::Dynamixel*>::iterator dxl_it = dxls.find(_joint_name);
461  if (dxl_it != dxls.end())
462  dxl = dxl_it->second;
463  else
464  continue;
465 
466  goal_position_.coeffRef(0, joint_index) = dxl->dxl_state_->goal_position_;
467  }
468 
469  processPhase(time_unit);
470 
471  bool get_angle = false;
472  get_angle = computeLegAngle(&angle[0]);
473 
474  computeArmAngle(&angle[12]);
475 
476  double rl_gyro_err = 0.0 - sensors["gyro_x"];
477  double fb_gyro_err = 0.0 - sensors["gyro_y"];
478 
479  sensoryFeedback(rl_gyro_err, fb_gyro_err, balance_angle);
480 
481  double err_total = 0.0, err_max = 0.0;
482  // set goal position
483  for (int idx = 0; idx < 14; idx++)
484  {
485  double goal_position = 0.0;
486  if (get_angle == false && idx < 12)
487  goal_position = goal_position_.coeff(0, idx);
488  else
489  goal_position = init_position_.coeff(0, idx) + angle[idx] + balance_angle[idx];
490 
491  target_position_.coeffRef(0, idx) = goal_position;
492 
493  double err = fabs(target_position_.coeff(0, idx) - goal_position_.coeff(0, idx)) * RADIAN2DEGREE;
494  if (err > err_max)
495  err_max = err;
496  err_total += err;
497  }
498 
499  // Check Enable
500  if (walking_state_ == WalkingEnable && err_total > 5.0)
501  {
502  if (DEBUG)
503  std::cout << "Check Err : " << err_max << std::endl;
504 
505  // make trajecotry for init pose
506  int mov_time = err_max / 30;
507  iniPoseTraGene(mov_time < 1 ? 1 : mov_time);
508 
509  // set target to goal
511 
513 
514  ROS_WARN_STREAM_COND(DEBUG, "x_offset: " << walking_param_.init_x_offset);
515  ROS_WARN_STREAM_COND(DEBUG, "y_offset: " << walking_param_.init_y_offset);
516  ROS_WARN_STREAM_COND(DEBUG, "z_offset: " << walking_param_.init_z_offset);
517  ROS_WARN_STREAM_COND(DEBUG, "roll_offset: " << walking_param_.init_roll_offset * RADIAN2DEGREE);
518  ROS_WARN_STREAM_COND(DEBUG, "pitch_offset: " << walking_param_.init_pitch_offset * RADIAN2DEGREE);
519  ROS_WARN_STREAM_COND(DEBUG, "yaw_offset: " << walking_param_.init_yaw_offset * RADIAN2DEGREE);
520  ROS_WARN_STREAM_COND(DEBUG, "hip_pitch_offset: " << walking_param_.hip_pitch_offset * RADIAN2DEGREE);
521  ROS_WARN_STREAM_COND(DEBUG, "period_time: " << walking_param_.period_time * 1000);
522  ROS_WARN_STREAM_COND(DEBUG, "dsp_ratio: " << walking_param_.dsp_ratio);
523  ROS_WARN_STREAM_COND(DEBUG, "step_forward_back_ratio: " << walking_param_.step_fb_ratio);
524  ROS_WARN_STREAM_COND(DEBUG, "foot_height: " << walking_param_.z_move_amplitude);
525  ROS_WARN_STREAM_COND(DEBUG, "swing_right_left: " << walking_param_.y_swap_amplitude);
526  ROS_WARN_STREAM_COND(DEBUG, "swing_top_down: " << walking_param_.z_swap_amplitude);
527  ROS_WARN_STREAM_COND(DEBUG, "pelvis_offset: " << walking_param_.pelvis_offset * RADIAN2DEGREE);
528  ROS_WARN_STREAM_COND(DEBUG, "arm_swing_gain: " << walking_param_.arm_swing_gain);
529  ROS_WARN_STREAM_COND(DEBUG, "balance_hip_roll_gain: " << walking_param_.balance_hip_roll_gain);
530  ROS_WARN_STREAM_COND(DEBUG, "balance_knee_gain: " << walking_param_.balance_knee_gain);
531  ROS_WARN_STREAM_COND(DEBUG, "balance_ankle_roll_gain: " << walking_param_.balance_ankle_roll_gain);
532  ROS_WARN_STREAM_COND(DEBUG, "balance_ankle_pitch_gain: " << walking_param_.balance_ankle_pitch_gain);
533  ROS_WARN_STREAM_COND(DEBUG, "balance : " << (walking_param_.balance_enable ? "TRUE" : "FALSE"));
534  }
535  else
536  {
538  }
539  }
540 
541  // set result
542  for (std::map<std::string, robotis_framework::DynamixelState *>::iterator state_it = result_.begin();
543  state_it != result_.end(); state_it++)
544  {
545  std::string joint_name = state_it->first;
546  int joint_index = joint_table_[joint_name];
547 
548  result_[joint_name]->goal_position_ = target_position_.coeff(0, joint_index);
549 
550  // Todo : setting PID gain to the leg joints
551  // result_[joint_name]->position_p_gain_ = walking_param_.p_gain;
552  // result_[joint_name]->position_i_gain_ = walking_param_.i_gain;
553  // result_[joint_name]->position_d_gain_ = walking_param_.d_gain;
554  }
555 
556  // time
557  if (real_running_ == true)
558  {
559  time_ += time_unit;
560  if (time_ >= period_time_)
561  {
562  time_ = 0;
563  previous_x_move_amplitude_ = walking_param_.x_move_amplitude * 0.5;
564  }
565  }
566 }
567 
568 void WalkingModule::processPhase(const double &time_unit)
569 {
570  // Update walk parameters
571  if (time_ == 0)
572  {
573  updateTimeParam();
574  phase_ = PHASE0;
575  if (ctrl_running_ == false)
576  {
577  if (x_move_amplitude_ == 0 && y_move_amplitude_ == 0 && a_move_amplitude_ == 0)
578  {
579  real_running_ = false;
580  }
581  else
582  {
583  // set walking param to init
584  walking_param_.x_move_amplitude = 0;
585  walking_param_.y_move_amplitude = 0;
586  walking_param_.angle_move_amplitude = 0;
587 
589  }
590  }
591  }
592  else if (time_ >= (phase1_time_ - time_unit / 2) && time_ < (phase1_time_ + time_unit / 2)) // the position of left foot is the highest.
593  {
595  phase_ = PHASE1;
596  }
597  else if (time_ >= (phase2_time_ - time_unit / 2) && time_ < (phase2_time_ + time_unit / 2)) // middle of double support state
598  {
599  updateTimeParam();
600 
602  phase_ = PHASE2;
603  if (ctrl_running_ == false)
604  {
605  if (x_move_amplitude_ == 0 && y_move_amplitude_ == 0 && a_move_amplitude_ == 0)
606  {
607  real_running_ = false;
608  }
609  else
610  {
611  // set walking param to init
612  walking_param_.x_move_amplitude = previous_x_move_amplitude_;
613  walking_param_.y_move_amplitude = 0;
614  walking_param_.angle_move_amplitude = 0;
615  }
616  }
617  }
618  else if (time_ >= (phase3_time_ - time_unit / 2) && time_ < (phase3_time_ + time_unit / 2)) // the position of right foot is the highest.
619  {
621  phase_ = PHASE3;
622  }
623 }
624 
625 bool WalkingModule::computeLegAngle(double *leg_angle)
626 {
627  Pose3D swap, right_leg_move, left_leg_move;
628  double pelvis_offset_r, pelvis_offset_l;
629  double ep[12];
630 
631  updatePoseParam();
632 
633  // Compute endpoints
637  swap.roll = 0.0;
638  swap.pitch = 0.0;
639  swap.yaw = 0.0;
640 
641  if (time_ <= l_ssp_start_time_)
642  {
643  left_leg_move.x = wSin(l_ssp_start_time_, x_move_period_time_,
646  left_leg_move.y = wSin(l_ssp_start_time_, y_move_period_time_,
647  y_move_phase_shift_ + 2 * M_PI / y_move_period_time_ * l_ssp_start_time_, y_move_amplitude_,
649  left_leg_move.z = wSin(l_ssp_start_time_, z_move_period_time_,
650  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * l_ssp_start_time_, z_move_amplitude_,
652  left_leg_move.yaw = wSin(l_ssp_start_time_, a_move_period_time_,
653  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * l_ssp_start_time_,
655  right_leg_move.x = wSin(l_ssp_start_time_, x_move_period_time_,
656  x_move_phase_shift_ + 2 * M_PI / x_move_period_time_ * l_ssp_start_time_,
658  right_leg_move.y = wSin(l_ssp_start_time_, y_move_period_time_,
659  y_move_phase_shift_ + 2 * M_PI / y_move_period_time_ * l_ssp_start_time_,
661  right_leg_move.z = wSin(r_ssp_start_time_, z_move_period_time_,
664  right_leg_move.yaw = wSin(l_ssp_start_time_, a_move_period_time_,
665  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * l_ssp_start_time_,
667  pelvis_offset_l = 0;
668  pelvis_offset_r = 0;
669  }
670  else if (time_ <= l_ssp_end_time_)
671  {
672  left_leg_move.x = wSin(time_, x_move_period_time_,
675  left_leg_move.y = wSin(time_, y_move_period_time_,
676  y_move_phase_shift_ + 2 * M_PI / y_move_period_time_ * l_ssp_start_time_, y_move_amplitude_,
678  left_leg_move.z = wSin(time_, z_move_period_time_,
679  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * l_ssp_start_time_, z_move_amplitude_,
681  left_leg_move.yaw = wSin(time_, a_move_period_time_,
682  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * l_ssp_start_time_,
684  right_leg_move.x = wSin(time_, x_move_period_time_,
685  x_move_phase_shift_ + 2 * M_PI / x_move_period_time_ * l_ssp_start_time_,
687  right_leg_move.y = wSin(time_, y_move_period_time_,
688  y_move_phase_shift_ + 2 * M_PI / y_move_period_time_ * l_ssp_start_time_,
690  right_leg_move.z = wSin(r_ssp_start_time_, z_move_period_time_,
693  right_leg_move.yaw = wSin(time_, a_move_period_time_,
694  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * l_ssp_start_time_,
696  pelvis_offset_l = wSin(time_, z_move_period_time_,
697  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * l_ssp_start_time_, pelvis_swing_ / 2,
698  pelvis_swing_ / 2);
699  pelvis_offset_r = wSin(time_, z_move_period_time_,
700  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * l_ssp_start_time_,
701  -pelvis_offset_ / 2, -pelvis_offset_ / 2);
702  }
703  else if (time_ <= r_ssp_start_time_)
704  {
705  left_leg_move.x = wSin(l_ssp_end_time_, x_move_period_time_,
708  left_leg_move.y = wSin(l_ssp_end_time_, y_move_period_time_,
709  y_move_phase_shift_ + 2 * M_PI / y_move_period_time_ * l_ssp_start_time_, y_move_amplitude_,
711  left_leg_move.z = wSin(l_ssp_end_time_, z_move_period_time_,
712  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * l_ssp_start_time_, z_move_amplitude_,
714  left_leg_move.yaw = wSin(l_ssp_end_time_, a_move_period_time_,
715  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * l_ssp_start_time_,
717  right_leg_move.x = wSin(l_ssp_end_time_, x_move_period_time_,
718  x_move_phase_shift_ + 2 * M_PI / x_move_period_time_ * l_ssp_start_time_,
720  right_leg_move.y = wSin(l_ssp_end_time_, y_move_period_time_,
721  y_move_phase_shift_ + 2 * M_PI / y_move_period_time_ * l_ssp_start_time_,
723  right_leg_move.z = wSin(r_ssp_start_time_, z_move_period_time_,
726  right_leg_move.yaw = wSin(l_ssp_end_time_, a_move_period_time_,
727  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * l_ssp_start_time_,
729  pelvis_offset_l = 0;
730  pelvis_offset_r = 0;
731  }
732  else if (time_ <= r_ssp_end_time_)
733  {
734  left_leg_move.x = wSin(time_, x_move_period_time_,
737  left_leg_move.y = wSin(time_, y_move_period_time_,
740  left_leg_move.z = wSin(l_ssp_end_time_, z_move_period_time_,
743  left_leg_move.yaw = wSin(time_, a_move_period_time_,
746  right_leg_move.x = wSin(time_, x_move_period_time_,
749  right_leg_move.y = wSin(time_, y_move_period_time_,
752  right_leg_move.z = wSin(time_, z_move_period_time_,
755  right_leg_move.yaw = wSin(time_, a_move_period_time_,
756  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * r_ssp_start_time_ + M_PI,
758  pelvis_offset_l = wSin(time_, z_move_period_time_,
759  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * r_ssp_start_time_, pelvis_offset_ / 2,
760  pelvis_offset_ / 2);
761  pelvis_offset_r = wSin(time_, z_move_period_time_,
762  z_move_phase_shift_ + 2 * M_PI / z_move_period_time_ * r_ssp_start_time_, -pelvis_swing_ / 2,
763  -pelvis_swing_ / 2);
764  }
765  else
766  {
767  left_leg_move.x = wSin(r_ssp_end_time_, x_move_period_time_,
770  left_leg_move.y = wSin(r_ssp_end_time_, y_move_period_time_,
773  left_leg_move.z = wSin(l_ssp_end_time_, z_move_period_time_,
776  left_leg_move.yaw = wSin(r_ssp_end_time_, a_move_period_time_,
779  right_leg_move.x = wSin(r_ssp_end_time_, x_move_period_time_,
782  right_leg_move.y = wSin(r_ssp_end_time_, y_move_period_time_,
785  right_leg_move.z = wSin(r_ssp_end_time_, z_move_period_time_,
788  right_leg_move.yaw = wSin(r_ssp_end_time_, a_move_period_time_,
789  a_move_phase_shift_ + 2 * M_PI / a_move_period_time_ * r_ssp_start_time_ + M_PI,
791  pelvis_offset_l = 0;
792  pelvis_offset_r = 0;
793  }
794 
795  left_leg_move.roll = 0;
796  left_leg_move.pitch = 0;
797  right_leg_move.roll = 0;
798  right_leg_move.pitch = 0;
799 
801 
802  // mm, rad
803  ep[0] = swap.x + right_leg_move.x + x_offset_;
804  ep[1] = swap.y + right_leg_move.y - y_offset_ / 2;
805  ep[2] = swap.z + right_leg_move.z + z_offset_ - leg_length;
806  ep[3] = swap.roll + right_leg_move.roll - r_offset_ / 2;
807  ep[4] = swap.pitch + right_leg_move.pitch + p_offset_;
808  ep[5] = swap.yaw + right_leg_move.yaw - a_offset_ / 2;
809  ep[6] = swap.x + left_leg_move.x + x_offset_;
810  ep[7] = swap.y + left_leg_move.y + y_offset_ / 2;
811  ep[8] = swap.z + left_leg_move.z + z_offset_ - leg_length;
812  ep[9] = swap.roll + left_leg_move.roll + r_offset_ / 2;
813  ep[10] = swap.pitch + left_leg_move.pitch + p_offset_;
814  ep[11] = swap.yaw + left_leg_move.yaw + a_offset_ / 2;
815 
816  // Compute body swing
817  if (time_ <= l_ssp_end_time_)
818  {
819  body_swing_y = -ep[7];
820  body_swing_z = ep[8];
821  }
822  else
823  {
824  body_swing_y = -ep[1];
825  body_swing_z = ep[2];
826  }
827  body_swing_z -= leg_length;
828 
829  // right leg
830  if (op3_kd_->calcInverseKinematicsForRightLeg(&leg_angle[0], ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]) == false)
831  {
832  printf("IK not Solved EPR : %f %f %f %f %f %f\n", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]);
833  return false;
834  }
835 
836  if (op3_kd_->calcInverseKinematicsForLeftLeg(&leg_angle[6], ep[6], ep[7], ep[8], ep[9], ep[10], ep[11]) == false)
837  {
838  printf("IK not Solved EPL : %f %f %f %f %f %f\n", ep[6], ep[7], ep[8], ep[9], ep[10], ep[11]);
839  return false;
840  }
841 
842  // Compute dxls angle
843  for (int i = 0; i < 12; i++)
844  {
845  // offset : rad
846  double offset = 0;
847 
848  if (i == joint_table_["r_hip_roll"]) // R_HIP_ROLL
849  offset += op3_kd_->getJointDirection("r_hip_roll") * pelvis_offset_r;
850  else if (i == joint_table_["l_hip_roll"]) // L_HIP_ROLL
851  offset += op3_kd_->getJointDirection("l_hip_roll") * pelvis_offset_l;
852  else if (i == joint_table_["r_hip_pitch"])
853  offset -= op3_kd_->getJointDirection("r_hip_pitch") * hit_pitch_offset_;
854  else if (i == joint_table_["l_hip_pitch"]) // R_HIP_PITCH or L_HIP_PITCH
855  offset -= op3_kd_->getJointDirection("l_hip_pitch") * hit_pitch_offset_;
856 
857  leg_angle[i] += offset;
858  }
859 
860  return true;
861 }
862 
863 void WalkingModule::computeArmAngle(double *arm_angle)
864 {
865  // Compute arm swing
866  if (x_move_amplitude_ == 0)
867  {
868  arm_angle[0] = 0; // Right
869  arm_angle[1] = 0; // Left
870  }
871  else
872  {
873  arm_angle[0] = wSin(time_, period_time_, M_PI * 1.5, -x_move_amplitude_ * arm_swing_gain_ * 1000,
874  0) * op3_kd_->getJointDirection("r_sho_pitch") * DEGREE2RADIAN;
875  arm_angle[1] = wSin(time_, period_time_, M_PI * 1.5, x_move_amplitude_ * arm_swing_gain_ * 1000,
876  0) * op3_kd_->getJointDirection("l_sho_pitch") * DEGREE2RADIAN;
877  }
878 }
879 
880 void WalkingModule::sensoryFeedback(const double &rlGyroErr, const double &fbGyroErr, double *balance_angle)
881 {
882  // adjust balance offset
883  if (walking_param_.balance_enable == false)
884  return;
885 
886  double internal_gain = 0.05;
887 
888  balance_angle[joint_table_["r_hip_roll"]] = op3_kd_->getJointDirection("r_hip_roll") * internal_gain
889  * rlGyroErr * walking_param_.balance_hip_roll_gain; // R_HIP_ROLL
890  balance_angle[joint_table_["l_hip_roll"]] = op3_kd_->getJointDirection("l_hip_roll") * internal_gain
891  * rlGyroErr * walking_param_.balance_hip_roll_gain; // L_HIP_ROLL
892 
893  balance_angle[joint_table_["r_knee"]] = - op3_kd_->getJointDirection("r_knee") * internal_gain
894  * fbGyroErr * walking_param_.balance_knee_gain; // R_KNEE
895  balance_angle[joint_table_["l_knee"]] = - op3_kd_->getJointDirection("l_knee") * internal_gain
896  * fbGyroErr * walking_param_.balance_knee_gain; // L_KNEE
897 
898  balance_angle[joint_table_["r_ank_pitch"]] = - op3_kd_->getJointDirection("r_ank_pitch")
899  * internal_gain * fbGyroErr * walking_param_.balance_ankle_pitch_gain; // R_ANKLE_PITCH
900  balance_angle[joint_table_["l_ank_pitch"]] = - op3_kd_->getJointDirection("l_ank_pitch")
901  * internal_gain * fbGyroErr * walking_param_.balance_ankle_pitch_gain; // L_ANKLE_PITCH
902 
903  balance_angle[joint_table_["r_ank_roll"]] = - op3_kd_->getJointDirection("r_ank_roll") * internal_gain
904  * rlGyroErr * walking_param_.balance_ankle_roll_gain; // R_ANKLE_ROLL
905  balance_angle[joint_table_["l_ank_roll"]] = - op3_kd_->getJointDirection("l_ank_roll") * internal_gain
906  * rlGyroErr * walking_param_.balance_ankle_roll_gain; // L_ANKLE_ROLL
907 
908 }
909 
910 void WalkingModule::loadWalkingParam(const std::string &path)
911 {
912  YAML::Node doc;
913  try
914  {
915  // load yaml
916  doc = YAML::LoadFile(path.c_str());
917  } catch (const std::exception& e)
918  {
919  ROS_ERROR("Fail to load yaml file.");
920  return;
921  }
922 
923  // parse movement time
924  walking_param_.init_x_offset = doc["x_offset"].as<double>();
925  walking_param_.init_y_offset = doc["y_offset"].as<double>();
926  walking_param_.init_z_offset = doc["z_offset"].as<double>();
927  walking_param_.init_roll_offset = doc["roll_offset"].as<double>() * DEGREE2RADIAN;
928  walking_param_.init_pitch_offset = doc["pitch_offset"].as<double>() * DEGREE2RADIAN;
929  walking_param_.init_yaw_offset = doc["yaw_offset"].as<double>() * DEGREE2RADIAN;
930  walking_param_.hip_pitch_offset = doc["hip_pitch_offset"].as<double>() * DEGREE2RADIAN;
931  // time
932  walking_param_.period_time = doc["period_time"].as<double>() * 0.001; // ms -> s
933  walking_param_.dsp_ratio = doc["dsp_ratio"].as<double>();
934  walking_param_.step_fb_ratio = doc["step_forward_back_ratio"].as<double>();
935  // walking
936  // walking_param_.x_move_amplitude
937  // walking_param_.y_move_amplitude
938  walking_param_.z_move_amplitude = doc["foot_height"].as<double>();
939  // walking_param_.angle_move_amplitude
940  // walking_param_.move_aim_on
941 
942  // balance
943  // walking_param_.balance_enable
944  walking_param_.balance_hip_roll_gain = doc["balance_hip_roll_gain"].as<double>();
945  walking_param_.balance_knee_gain = doc["balance_knee_gain"].as<double>();
946  walking_param_.balance_ankle_roll_gain = doc["balance_ankle_roll_gain"].as<double>();
947  walking_param_.balance_ankle_pitch_gain = doc["balance_ankle_pitch_gain"].as<double>();
948  walking_param_.y_swap_amplitude = doc["swing_right_left"].as<double>();
949  walking_param_.z_swap_amplitude = doc["swing_top_down"].as<double>();
950  walking_param_.pelvis_offset = doc["pelvis_offset"].as<double>() * DEGREE2RADIAN;
951  walking_param_.arm_swing_gain = doc["arm_swing_gain"].as<double>();
952 
953  // gain
954  walking_param_.p_gain = doc["p_gain"].as<int>();
955  walking_param_.i_gain = doc["i_gain"].as<int>();
956  walking_param_.d_gain = doc["d_gain"].as<int>();
957 }
958 
959 void WalkingModule::saveWalkingParam(std::string &path)
960 {
961  YAML::Emitter out_emitter;
962 
963  out_emitter << YAML::BeginMap;
964  out_emitter << YAML::Key << "x_offset" << YAML::Value << walking_param_.init_x_offset;
965  out_emitter << YAML::Key << "y_offset" << YAML::Value << walking_param_.init_y_offset;
966  out_emitter << YAML::Key << "z_offset" << YAML::Value << walking_param_.init_z_offset;
967  out_emitter << YAML::Key << "roll_offset" << YAML::Value << walking_param_.init_roll_offset * RADIAN2DEGREE;
968  out_emitter << YAML::Key << "pitch_offset" << YAML::Value << walking_param_.init_pitch_offset * RADIAN2DEGREE;
969  out_emitter << YAML::Key << "yaw_offset" << YAML::Value << walking_param_.init_yaw_offset * RADIAN2DEGREE;
970  out_emitter << YAML::Key << "hip_pitch_offset" << YAML::Value << walking_param_.hip_pitch_offset * RADIAN2DEGREE;
971  out_emitter << YAML::Key << "period_time" << YAML::Value << walking_param_.period_time * 1000;
972  out_emitter << YAML::Key << "dsp_ratio" << YAML::Value << walking_param_.dsp_ratio;
973  out_emitter << YAML::Key << "step_forward_back_ratio" << YAML::Value << walking_param_.step_fb_ratio;
974  out_emitter << YAML::Key << "foot_height" << YAML::Value << walking_param_.z_move_amplitude;
975  out_emitter << YAML::Key << "swing_right_left" << YAML::Value << walking_param_.y_swap_amplitude;
976  out_emitter << YAML::Key << "swing_top_down" << YAML::Value << walking_param_.z_swap_amplitude;
977  out_emitter << YAML::Key << "pelvis_offset" << YAML::Value << walking_param_.pelvis_offset * RADIAN2DEGREE;
978  out_emitter << YAML::Key << "arm_swing_gain" << YAML::Value << walking_param_.arm_swing_gain;
979  out_emitter << YAML::Key << "balance_hip_roll_gain" << YAML::Value << walking_param_.balance_hip_roll_gain;
980  out_emitter << YAML::Key << "balance_knee_gain" << YAML::Value << walking_param_.balance_knee_gain;
981  out_emitter << YAML::Key << "balance_ankle_roll_gain" << YAML::Value << walking_param_.balance_ankle_roll_gain;
982  out_emitter << YAML::Key << "balance_ankle_pitch_gain" << YAML::Value << walking_param_.balance_ankle_pitch_gain;
983 
984  out_emitter << YAML::Key << "p_gain" << YAML::Value << walking_param_.p_gain;
985  out_emitter << YAML::Key << "i_gain" << YAML::Value << walking_param_.i_gain;
986  out_emitter << YAML::Key << "d_gain" << YAML::Value << walking_param_.d_gain;
987  out_emitter << YAML::EndMap;
988 
989  // output to file
990  std::ofstream fout(path.c_str());
991  fout << out_emitter.c_str();
992 }
993 
995 {
997  ROS_INFO("Walking Enable");
998 }
999 
1001 {
1002  ROS_INFO("Walking Disable");
1004 }
1005 
1006 void WalkingModule::iniPoseTraGene(double mov_time)
1007 {
1008  double smp_time = control_cycle_msec_ * 0.001;
1009  int all_time_steps = int(mov_time / smp_time) + 1;
1010  calc_joint_tra_.resize(all_time_steps, result_.size() + 1);
1011 
1012  for (int id = 0; id <= result_.size(); id++)
1013  {
1014  double ini_value = goal_position_.coeff(0, id);
1015  double tar_value = target_position_.coeff(0, id);
1016 
1017  Eigen::MatrixXd tra;
1018 
1019  tra = robotis_framework::calcMinimumJerkTra(ini_value, 0.0, 0.0, tar_value, 0.0, 0.0, smp_time, mov_time);
1020 
1021  calc_joint_tra_.block(0, id, all_time_steps, 1) = tra;
1022  }
1023 
1024  if(DEBUG)
1025  std::cout << "Generate Trajecotry : " << mov_time << "s [" << all_time_steps << "]" << std::endl;
1026 
1027  init_pose_count_ = 0;
1028 }
1029 }
std::map< std::string, DynamixelState * > result_
bool computeLegAngle(double *leg_angle)
Eigen::MatrixXd calcMinimumJerkTra(double pos_start, double vel_start, double accel_start, double pos_end, double vel_end, double accel_end, double smp_time, double mov_time)
void publish(const boost::shared_ptr< M > &message) const
OP3KinematicsDynamics * op3_kd_
void initialize(const int control_cycle_msec, robotis_framework::Robot *robot)
void walkingCommandCallback(const std_msgs::String::ConstPtr &msg)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void publishStatusMsg(unsigned int type, std::string msg)
Eigen::Matrix4d getInverseTransformation(const Eigen::MatrixXd &transform)
#define RADIAN2DEGREE
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
Eigen::MatrixXi joint_axis_direction_
void process(std::map< std::string, robotis_framework::Dynamixel * > dxls, std::map< std::string, double > sensors)
#define ROS_WARN(...)
Eigen::Matrix4d getTransformationXYZRPY(double position_x, double position_y, double position_z, double roll, double pitch, double yaw)
op3_walking_module_msgs::WalkingParam walking_param_
double getJointDirection(const std::string link_name)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void setCallbackQueue(CallbackQueueInterface *queue)
#define DEGREE2RADIAN
double wSin(double time, double period, double period_shift, double mag, double mag_shift)
#define ROS_WARN_STREAM_COND(cond, args)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
void walkingParameterCallback(const op3_walking_module_msgs::WalkingParam::ConstPtr &msg)
void saveWalkingParam(std::string &path)
ROSLIB_DECL std::string getPath(const std::string &package_name)
void loadWalkingParam(const std::string &path)
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
void processPhase(const double &time_unit)
DynamixelState * dxl_state_
bool getWalkigParameterCallback(op3_walking_module_msgs::GetWalkingParam::Request &req, op3_walking_module_msgs::GetWalkingParam::Response &res)
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
static Time now()
bool computeIK(double *out, double x, double y, double z, double a, double b, double c)
bool calcInverseKinematicsForRightLeg(double *out, double x, double y, double z, double roll, double pitch, double yaw)
bool ok() const
bool calcInverseKinematicsForLeftLeg(double *out, double x, double y, double z, double roll, double pitch, double yaw)
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
void swap(scoped_ptr< T > &, scoped_ptr< T > &)
std::map< std::string, int > joint_table_
#define ROS_ERROR(...)
void computeArmAngle(double *arm_angle)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
void sensoryFeedback(const double &rlGyroErr, const double &fbGyroErr, double *balance_angle)
void iniPoseTraGene(double mov_time)


op3_walking_module
Author(s): Kayman
autogenerated on Mon Jun 10 2019 14:41:25