Tetrapod Project
miqp_waypoint.cpp
Go to the documentation of this file.
2 
3 #include "ros/console.h"
4 
5 #include<cmath>
6 
8 
9 #define _USE_MATH_DEFINES
10 
11 namespace miqp{
12 namespace waypoint{
13 
14 using drake::solvers::MatrixXDecisionVariable;
15 
16 using drake::symbolic::sin;
17 
18 using drake::symbolic::cos;
19 
20 DecVars add_decision_variables(drake::solvers::MathematicalProgram &prog, Terrain &terrain, int n_points){
21  int n_stones = terrain.getSteppingStones().rows();
22 
23  DecVars decision_variables;
24 
25  decision_variables.position_center = prog.NewContinuousVariables(n_points, 2, "position_center");
26 
27  decision_variables.position_front_left = prog.NewContinuousVariables(n_points, 2, "position_front_left");
28 
29  decision_variables.position_front_right = prog.NewContinuousVariables(n_points, 2, "position_front_right");
30 
31  decision_variables.position_rear_left = prog.NewContinuousVariables(n_points, 2, "position_rear_left");
32 
33  decision_variables.position_rear_right = prog.NewContinuousVariables(n_points, 2, "position_rear_right");
34 
35  decision_variables.stone_front_left = prog.NewBinaryVariables(n_points, n_stones, "stone_front_left");
36 
37  decision_variables.stone_front_right = prog.NewBinaryVariables(n_points, n_stones, "stone_front_right");
38 
39  decision_variables.stone_rear_left = prog.NewBinaryVariables(n_points, n_stones, "stone_rear_left");
40 
41  decision_variables.stone_rear_right = prog.NewBinaryVariables(n_points, n_stones, "stone_rear_right");
42 
43  decision_variables.theta = prog.NewContinuousVariables(n_points, 1, "theta");
44 
45  decision_variables.lin_sin = prog.NewContinuousVariables(n_points, 1, "sin_theta");
46 
47  decision_variables.lin_cos = prog.NewContinuousVariables(n_points, 1, "cos_theta");
48 
49  decision_variables.bin_sin = prog.NewBinaryVariables(n_points, 5, "sin_selection");
50 
51  decision_variables.bin_cos = prog.NewBinaryVariables(n_points, 5, "cos_selection");
52 
53  return decision_variables;
54 }
55 
56 void set_initial_and_goal_position(drake::solvers::MathematicalProgram &prog, Eigen::Vector2d &initial_center, Eigen::Vector2d &goal_center, DecVars &decision_variables)
57 {
58  MatrixXDecisionVariable &position_center = decision_variables.position_center;
59 
60  MatrixXDecisionVariable &theta = decision_variables.theta;
61 
62  prog.AddLinearConstraint(position_center.row(0).transpose() == initial_center);
63 
64  prog.AddLinearConstraint(position_center.row(position_center.rows() - 1).transpose() == goal_center);
65 
66  prog.AddLinearConstraint(theta(0) == 0);
67 
68  prog.AddLinearConstraint(theta(theta.rows() - 1) == 0);
69 }
70 
71 void relative_position_limits(drake::solvers::MathematicalProgram &prog, int n_points, double wp_dist, DecVars &decision_variables)
72 {
73  MatrixXDecisionVariable &position_center = decision_variables.position_center;
74 
75  for (int i = 0; i < n_points - 1; ++i)
76  {
77  prog.AddLinearConstraint(position_center.row(i + 1).transpose() - position_center.row(i).transpose() <= Eigen::Vector2d::Constant(wp_dist));
78 
79  prog.AddLinearConstraint(position_center.row(i + 1).transpose() - position_center.row(i).transpose() >= Eigen::Vector2d::Constant(-wp_dist));
80  }
81 }
82 
83 void geometry_limits(drake::solvers::MathematicalProgram &prog, int n_points, double length_legs, double bbox_len, DecVars &decision_variables)
84 {
85  MatrixXDecisionVariable &position_center = decision_variables.position_center;
86 
87  MatrixXDecisionVariable &position_front_left = decision_variables.position_front_left;
88 
89  MatrixXDecisionVariable &position_front_right = decision_variables.position_front_right;
90 
91  MatrixXDecisionVariable &position_rear_left = decision_variables.position_rear_left;
92 
93  MatrixXDecisionVariable &position_rear_right = decision_variables.position_rear_right;
94 
95  MatrixXDecisionVariable &lin_sin = decision_variables.lin_sin;
96 
97  MatrixXDecisionVariable &lin_cos = decision_variables.lin_cos;
98 
99  //MatrixXDecisionVariable &sequence_offset = decision_variables.sequence_offset;
100  int n_legs = 4;
101 
102  double angle_divided = 2*M_PI/n_legs;
103 
104  double phis[] = {0.5*angle_divided, -0.5*angle_divided, 1.5*angle_divided, -1.5*angle_divided};
105 
106  Eigen::Matrix<drake::symbolic::Expression, 2, 1> leg_offset;
107 
108  for (int i = 0; i < n_points; ++i)
109  {
110  leg_offset << length_legs*(lin_cos(i)*cos(phis[front_left]) - lin_sin(i)*sin(phis[front_left])),
111 
112  length_legs*(lin_sin(i)*cos(phis[front_left]) + lin_cos(i)*sin(phis[front_left]));
113 
114  prog.AddLinearConstraint(position_front_left.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) <= Eigen::Vector2d::Constant(bbox_len/2));
115 
116  prog.AddLinearConstraint(position_front_left.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) >= Eigen::Vector2d::Constant(-bbox_len/2));
117 
118  leg_offset << length_legs*(lin_cos(i)*cos(phis[front_right]) - lin_sin(i)*sin(phis[front_right])),
119 
120  length_legs*(lin_sin(i)*cos(phis[front_right]) + lin_cos(i)*sin(phis[front_right]));
121 
122  prog.AddLinearConstraint(position_front_right.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) <= Eigen::Vector2d::Constant(bbox_len/2));
123 
124  prog.AddLinearConstraint(position_front_right.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) >= Eigen::Vector2d::Constant(-bbox_len/2));
125 
126  leg_offset << length_legs*(lin_cos(i)*cos(phis[rear_left]) - lin_sin(i)*sin(phis[rear_left])),
127 
128  length_legs*(lin_sin(i)*cos(phis[rear_left]) + lin_cos(i)*sin(phis[rear_left]));
129 
130  prog.AddLinearConstraint(position_rear_left.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) <= Eigen::Vector2d::Constant(bbox_len/2));
131 
132  prog.AddLinearConstraint(position_rear_left.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) >= Eigen::Vector2d::Constant(-bbox_len/2));
133 
134  leg_offset << length_legs*(lin_cos(i)*cos(phis[rear_right]) - lin_sin(i)*sin(phis[rear_right])),
135 
136  length_legs*(lin_sin(i)*cos(phis[rear_right]) + lin_cos(i)*sin(phis[rear_right]));
137 
138  prog.AddLinearConstraint(position_rear_right.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) <= Eigen::Vector2d::Constant(bbox_len/2));
139 
140  prog.AddLinearConstraint(position_rear_right.row(i).transpose() - (position_center.row(i).transpose() + leg_offset) >= Eigen::Vector2d::Constant(-bbox_len/2));
141  }
142 }
143 
144 void theta_limits(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
145 {
146  MatrixXDecisionVariable &theta = decision_variables.theta;
147 
148  MatrixXDecisionVariable &lin_sin = decision_variables.lin_sin;
149 
150  MatrixXDecisionVariable &lin_cos = decision_variables.lin_cos;
151 
152  MatrixXDecisionVariable &bin_sin = decision_variables.bin_sin;
153 
154  MatrixXDecisionVariable &bin_cos = decision_variables.bin_cos;
155 
156  double big_M = 2*M_PI;
157 
158  double sin_dividers[] = {0, 1, M_PI - 1, M_PI + 1, 2*M_PI - 1, 2*M_PI};
159 
160  double cos_dividers[] = {0, M_PI/2 - 1, M_PI/2 + 1, 3*M_PI/2 - 1, 3*M_PI/2 + 1, 2*M_PI};
161 
162  Eigen::Matrix<double, 5, 2> sin_coeffs = get_sin_coeffs();
163 
164  Eigen::Matrix<double, 5, 2> cos_coeffs = get_cos_coeffs();
165 
166  ROS_INFO("Right before loop");
167  for (int i = 0; i < n_points; ++i)
168  {
169  // enforce theta to be within first cycle
170  prog.AddLinearConstraint(theta(i) >= 0);
171 
172  prog.AddLinearConstraint(theta(i) <= 2*M_PI);
173 
174  // enforce relation between theta and binary variables
175  ROS_INFO("About to add relation between theta and bin constr");
176  for (int l = 0; l < 5; ++l)
177  {
178  prog.AddLinearConstraint(theta(i) >= sin_dividers[l] - (1 - bin_sin(i, l))*big_M);
179 
180  prog.AddLinearConstraint(theta(i) <= sin_dividers[l + 1] + (1 - bin_sin(i, l))*big_M);
181 
182  prog.AddLinearConstraint(theta(i) >= cos_dividers[l] - (1 - bin_cos(i, l))*big_M);
183 
184  prog.AddLinearConstraint(theta(i) <= cos_dividers[l + 1] + (1 - bin_cos(i, l))*big_M);
185  }
186  ROS_INFO("About to enforce exactly one line segment");
187  // enforce that exactly one line segment must be active at a time
188  auto sin_const = prog.AddLinearConstraint((bin_sin.row(i)*Eigen::VectorXd::Ones(5))(0) == 1);
189 
190  auto cos_const = prog.AddLinearConstraint((bin_cos.row(i)*Eigen::VectorXd::Ones(5))(0) == 1);
191 
192  // enforce linearized sin_theta according to which binary selection variable is active
193  ROS_INFO("About to enforce linearized sin_theta/cos_theta");
194  auto sin_upper = prog.AddLinearConstraint(lin_sin(i) - (sin_coeffs.col(0) + sin_coeffs.col(1)*theta(i))(0) <= big_M);
195 
196  auto sin_lower = prog.AddLinearConstraint(lin_sin(i) - (sin_coeffs.col(0) + sin_coeffs.col(1)*theta(i))(0) >= -big_M);
197 
198  auto cos_upper = prog.AddLinearConstraint(lin_cos(i) - (cos_coeffs.col(0) + cos_coeffs.col(1)*theta(i))(0) <= big_M);
199 
200  auto cos_lower = prog.AddLinearConstraint(lin_cos(i) - (cos_coeffs.col(0) + cos_coeffs.col(1)*theta(i))(0) >= -big_M);
201 
202  std::cout << sin_upper << std::endl << sin_lower << std::endl << cos_upper << std::endl << cos_lower << std::endl;
203  }
204 }
205 
206 void one_stone_per_foot(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
207 {
208  MatrixXDecisionVariable &stone_front_left = decision_variables.stone_front_left;
209 
210  MatrixXDecisionVariable &stone_front_right = decision_variables.stone_front_right;
211 
212  MatrixXDecisionVariable &stone_rear_left = decision_variables.stone_rear_left;
213 
214  MatrixXDecisionVariable &stone_rear_right = decision_variables.stone_rear_right;
215 
216  prog.AddLinearConstraint(stone_front_left*Eigen::VectorXd::Ones(stone_front_left.cols()) == Eigen::VectorXd::Ones(stone_front_left.rows()));
217 
218  prog.AddLinearConstraint(stone_front_right*Eigen::VectorXd::Ones(stone_front_right.cols()) == Eigen::VectorXd::Ones(stone_front_right.rows()));
219 
220  prog.AddLinearConstraint(stone_rear_left*Eigen::VectorXd::Ones(stone_rear_left.cols()) == Eigen::VectorXd::Ones(stone_rear_left.rows()));
221 
222  prog.AddLinearConstraint(stone_rear_right*Eigen::VectorXd::Ones(stone_rear_right.cols()) == Eigen::VectorXd::Ones(stone_rear_right.rows()));
223 
224 }
225 
226 Eigen::Vector4d get_big_M(Terrain terrain)
227 {
228  SteppingStone initial = terrain.getStoneByName("initial");
229 
230  SteppingStone goal = terrain.getStoneByName("goal");
231 
232  SteppingStone lateral = terrain.getStoneByName("lateral");
233 
234  Eigen::Vector2d M(goal.getCenter()(0) - initial.getCenter()(0), lateral.getTopRight()(1) - initial.getCenter()(1));
235 
236  Eigen::Vector4d res;
237 
238  res << M, M;
239  return res;
240 }
241 
242 void foot_in_stepping_stone(drake::solvers::MathematicalProgram &prog, Terrain &terrain, int n_points, DecVars &decision_variables)
243 {
244  MatrixXDecisionVariable &position_front_left = decision_variables.position_front_left;
245 
246  MatrixXDecisionVariable &position_front_right = decision_variables.position_front_right;
247 
248  MatrixXDecisionVariable &position_rear_left = decision_variables.position_rear_left;
249 
250  MatrixXDecisionVariable &position_rear_right = decision_variables.position_rear_right;
251 
252  MatrixXDecisionVariable &stone_front_left = decision_variables.stone_front_left;
253 
254  MatrixXDecisionVariable &stone_front_right = decision_variables.stone_front_right;
255 
256  MatrixXDecisionVariable &stone_rear_left = decision_variables.stone_rear_left;
257 
258  MatrixXDecisionVariable &stone_rear_right = decision_variables.stone_rear_right;
259 
260  Eigen::Vector4d M = get_big_M(terrain);
261 
262  int n_stones = terrain.getSteppingStones().rows();
263 
264  Eigen::MatrixXd A, b;
265  for (int i = 0; i < n_points; ++i)
266  {
267  for (int l = 0; l < n_stones ; ++l)
268  {
269  A = terrain.getSteppingStones()(l).getA();
270 
271  b = terrain.getSteppingStones()(l).getB();
272 
273  prog.AddLinearConstraint(A*position_front_left.row(i).transpose() <= b + (1 - stone_front_left(i, l))*M);
274 
275  prog.AddLinearConstraint(A*position_front_right.row(i).transpose() <= b + (1 - stone_front_right(i, l))*M);
276 
277  prog.AddLinearConstraint(A*position_rear_left.row(i).transpose() <= b + (1 - stone_rear_left(i, l))*M);
278 
279  prog.AddLinearConstraint(A*position_rear_right.row(i).transpose() <= b + (1 - stone_rear_right(i, l))*M);
280 
281  }
282  }
283 }
284 
285 void minimize_step_length(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
286 {
287  MatrixXDecisionVariable &position_center = decision_variables.position_center;
288 
289  Eigen::Matrix<drake::symbolic::Expression, 2, 1> dist;
290 
291  for (int i = 0; i < n_points - 1; ++i)
292  {
293  dist = (position_center.row(i + 1) - position_center.row(i)).transpose();
294 
295  prog.AddQuadraticCost((dist.transpose()*dist)(0));
296  }
297 }
298 
299 void minimize_theta_change(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
300 {
301  //Trying to use square of difference in trig functions to avoid challenges related to wrapping discontinuities
302 
303  MatrixXDecisionVariable &lin_sin = decision_variables.lin_sin;
304 
305  MatrixXDecisionVariable &lin_cos = decision_variables.lin_cos;
306 
307  drake::symbolic::Expression sin_dist;
308 
309  drake::symbolic::Expression cos_dist;
310 
311  for (int i = 0; i < n_points - 1; ++i)
312  {
313  sin_dist = lin_sin(i + 1) - lin_sin(i);
314 
315  cos_dist = lin_cos(i + 1) - lin_cos(i);
316 
317  prog.AddQuadraticCost(sin_dist*sin_dist);
318 
319  prog.AddQuadraticCost(cos_dist*cos_dist);
320  }
321 }
322 
323 void writeMatToFile(Eigen::MatrixXd &mat, std::string filename)
324 {
325  std::ofstream file(filename);
326 
327  if (file.is_open())
328  {
329  file.clear();
330 
331  file << mat;
332 
333  ROS_INFO("writeMatToFile: Successfully wrote to file");
334  } else
335  {
336  ROS_ERROR("could not open file");
337 
338  throw "could not open file " + filename;
339  }
340 
341  file.close();
342 }
343 
344 void writeDecVarsToFile(DecVars_res &decision_variables, std::string base_name)
345 {
346  std::string fend = ".csv";
347 
348  writeMatToFile(decision_variables.position_front_left, base_name + "_position_front_left" + fend);
349 
350  writeMatToFile(decision_variables.position_front_right, base_name + "_position_front_right" + fend);
351 
352  writeMatToFile(decision_variables.position_rear_left, base_name + "_position_rear_left" + fend);
353 
354  writeMatToFile(decision_variables.position_rear_right, base_name + "_position_rear_right" + fend);
355 
356  writeMatToFile(decision_variables.stone_front_left, base_name + "_stone_front_left" + fend);
357 
358  writeMatToFile(decision_variables.stone_front_right, base_name + "_stone_front_right" + fend);
359 
360  writeMatToFile(decision_variables.stone_rear_left, base_name + "_stone_rear_left" + fend);
361 
362  writeMatToFile(decision_variables.stone_rear_right, base_name + "_stone_rear_right" + fend);
363 }
364 
365 }
366 }
const Eigen::Vector3d & getCenter() const
const Eigen::Vector3d & getTopRight() const
const SteppingStone & getStoneByName(std::string name) const
Definition: terrain.cpp:95
const Eigen::Array< SteppingStone, Eigen::Dynamic, 1 > & getSteppingStones() const
Definition: terrain.h:23
DecVars add_decision_variables(drake::solvers::MathematicalProgram &prog, Terrain &terrain, int n_points)
void set_initial_and_goal_position(drake::solvers::MathematicalProgram &prog, Eigen::Vector2d &initial_center, Eigen::Vector2d &goal_center, DecVars &decision_variables)
void one_stone_per_foot(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
void foot_in_stepping_stone(drake::solvers::MathematicalProgram &prog, Terrain &terrain, int n_points, DecVars &decision_variables)
void minimize_step_length(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
Eigen::Vector4d get_big_M(Terrain terrain)
void geometry_limits(drake::solvers::MathematicalProgram &prog, int n_points, double length_legs, double bbox_len, DecVars &decision_variables)
void relative_position_limits(drake::solvers::MathematicalProgram &prog, int n_points, double wp_dist, DecVars &decision_variables)
void writeDecVarsToFile(DecVars_res &decision_variables, std::string base_name)
void theta_limits(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
void minimize_theta_change(drake::solvers::MathematicalProgram &prog, int n_points, DecVars &decision_variables)
void writeMatToFile(Eigen::MatrixXd &mat, std::string filename)
Eigen::MatrixXd position_front_right
Definition: miqp_waypoint.h:60
Eigen::MatrixXd stone_front_left
Definition: miqp_waypoint.h:66
Eigen::MatrixXd position_front_left
Definition: miqp_waypoint.h:58
Eigen::MatrixXd position_rear_left
Definition: miqp_waypoint.h:62
Eigen::MatrixXd stone_rear_right
Definition: miqp_waypoint.h:72
Eigen::MatrixXd stone_rear_left
Definition: miqp_waypoint.h:70
Eigen::MatrixXd position_rear_right
Definition: miqp_waypoint.h:64
Eigen::MatrixXd stone_front_right
Definition: miqp_waypoint.h:68
MatrixXDecisionVariable stone_front_left
Definition: miqp_waypoint.h:36
MatrixXDecisionVariable bin_cos
Definition: miqp_waypoint.h:48
MatrixXDecisionVariable theta
Definition: miqp_waypoint.h:44
MatrixXDecisionVariable stone_front_right
Definition: miqp_waypoint.h:38
MatrixXDecisionVariable position_front_left
Definition: miqp_waypoint.h:28
MatrixXDecisionVariable position_front_right
Definition: miqp_waypoint.h:30
MatrixXDecisionVariable position_rear_right
Definition: miqp_waypoint.h:34
MatrixXDecisionVariable lin_cos
Definition: miqp_waypoint.h:52
MatrixXDecisionVariable stone_rear_right
Definition: miqp_waypoint.h:42
MatrixXDecisionVariable position_center
Definition: miqp_waypoint.h:26
MatrixXDecisionVariable bin_sin
Definition: miqp_waypoint.h:46
MatrixXDecisionVariable lin_sin
Definition: miqp_waypoint.h:50
MatrixXDecisionVariable stone_rear_left
Definition: miqp_waypoint.h:40
MatrixXDecisionVariable position_rear_left
Definition: miqp_waypoint.h:32
Eigen::MatrixXd get_cos_coeffs()
Definition: utils.cpp:40
Eigen::MatrixXd get_sin_coeffs()
Definition: utils.cpp:28