A sparse MPC solver for walking motion generation.
walking.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @author Antonio Paolillo
4  * @author Dimitar Dimitrov
5  * @author Alexander Sherikov
6  */
7 
8 #include "oru_walk.h"
9 #include "oruw_log.h"
10 #include "oruw_timer.h"
11 
12 
13 /**
14  * @brief Construct and initialize all necessary classes and register
15  * callback function.
16  */
18 {
21 
22 
23  // initialize Nao model
24  readSensors(nao.state_sensor);
25 
26 
27  // start walk control thread
28  try
29  {
30  boost::thread walk_control_thread(&oru_walk::walkControl, this);
31  struct sched_param walk_control_thread_sched;
32 
33  walk_control_thread_sched.sched_priority = wp.walk_control_thread_priority;
34  int retval = pthread_setschedparam(
35  walk_control_thread.native_handle(),
36  SCHED_FIFO,
37  &walk_control_thread_sched);
38  if (retval != 0)
39  {
40  // Assume that this error is not critical
41  ORUW_LOG_MESSAGE("Cannot change the priority of the walk control thread: %s\n", strerror(retval));
42  }
43 
44  walk_control_thread.detach();
45  }
46  catch (...)
47  {
48  halt("Failed to spawn the walk control thread.\n", __FUNCTION__);
49  }
50 
51 
52  // register callback
53  dcm_loop_counter = 0;
54  try
55  {
57  getParentBroker()->getProxy("DCM")->getModule()->atPostProcess
58  (boost::bind(&oru_walk::dcmCallback, this));
59  }
60  catch (const ALError &e)
61  {
62  ORUW_LOG_MESSAGE("Callback registration failed: %s\n", e.what());
63  halt("Callback registration failed!", __FUNCTION__);
64  }
65 }
66 
67 
68 
69 /**
70  * @brief Update joint angles.
71  */
72 void oru_walk::readSensors(jointState& joint_state)
73 {
74  vector<float> sensorValues;
75 
76  access_sensor_values->GetValues (sensorValues);
77  for (int i = 0; i < JOINTS_NUM; i++)
78  {
79  joint_state.q[i] = sensorValues[i];
80  }
81  /* Acc. to the documentation:
82  * "LHipYawPitch and RHipYawPitch share the same motor so they move
83  * simultaneously and symmetrically. In case of conflicting orders,
84  * LHipYawPitch always takes the priority."
85  * Make sure that these joint angles are equal:
86  */
87  joint_state.q[R_HIP_YAW_PITCH] = joint_state.q[L_HIP_YAW_PITCH];
88 }
89 
90 
91 
92 /**
93  * @brief Wake up walk control thread periodically.
94  */
96 {
99  {
101  readSensors (nao.state_sensor);
102 
103  boost::mutex::scoped_lock lock(walk_control_mutex);
104  walk_control_condition.notify_one();
105  lock.unlock();
106  }
107 }
108 
109 
110 
111 /**
112  * @brief The position of the next support foot may change from the targeted,
113  * this function moves it to the right place.
114  */
116 {
117  Transform<double,3> swing_foot_posture;
118  nao.getSwingFootPosture (nao.state_sensor, swing_foot_posture.data());
119  wmg.changeNextSSPosition (swing_foot_posture.data(), wp.set_support_z_to_zero);
120 }
121 
122 
123 /**
124  * @brief Initialize solver
125  */
127 {
128  if (solver != NULL)
129  {
130  delete solver;
131  solver = NULL;
132  }
134  {
135  solver = new smpc::solver_as (
144  false); // objective
145  }
146  else if (wp.mpc_solver_type == SOLVER_TYPE_IP)
147  {
148  solver = new smpc::solver_ip (
156  wp.mpc_ip_t,
157  wp.mpc_ip_mu,
161  (smpc::backtrackingSearchType) wp.mpc_ip_bs_type,
162  false); // objective
163  }
164 // smpc::enable_fexceptions();
165 }
166 
167 
168 
169 /**
170  * @brief A control loop, that is executed in separate thread.
171  * @attention REAL-TIME!
172  */
174 {
175  oruw_timer timer(__FUNCTION__, wp.loop_time_limit_ms);
176 
177 
178  initSolver();
179 
180 
181  WMG wmg(wp.preview_window_size,
183  wp.step_height,
188  wmg.T_ms[0] = wp.control_sampling_time_ms;
189  wmg.T_ms[1] = wp.control_sampling_time_ms;
190 
191 
192  smpc::state_com CoM;
193 
194 
195  try
196  {
197  // steps
198  initWalkPattern(wmg);
199  // error in position of the swing foot
201  }
202  catch (...)
203  {
204  return;
205  }
206 
207 
208  nao.getCoM (nao.state_sensor, nao.CoM_position);
209  smpc_parameters mpc(wp.preview_window_size, nao.CoM_position[2]);
210  mpc.init_state.set (nao.CoM_position[0], nao.CoM_position[1]);
211 
212 
213  jointState target_joint_state = nao.state_model;
214  for (;;)
215  {
216  boost::unique_lock<boost::mutex> lock(walk_control_mutex);
217  walk_control_condition.wait(lock);
218  lock.unlock();
219 
220 
221  timer.reset();
222 
223 
224  ORUW_LOG_JOINTS(nao.state_sensor, target_joint_state);
225  ORUW_LOG_COM(mpc, nao);
227 
228 
229  try
230  {
231  feedbackError (mpc.init_state);
232 
233  if (solveMPCProblem (wmg, mpc)) // solve MPC
234  {
235  if (wmg.isSupportSwitchNeeded())
236  {
238  nao.switchSupportFoot();
239  }
240 
241  // the old solution from is an initial guess;
242  solver->get_state(CoM, 0);
243  solveIKsendCommands (mpc, CoM, 1, wmg);
244  target_joint_state = nao.state_model;
245  solver->get_state(CoM, 1);
246  solveIKsendCommands (mpc, CoM, 2, wmg);
247  }
248  else
249  {
250  break;
251  }
252 
253  if (!timer.check())
254  {
255  halt("Time limit is violated!\n", __FUNCTION__);
256  }
257  }
258  catch (...)
259  {
260  break;
261  }
262  }
263 
264  ORUW_LOG_STEPS(wmg);
266 }
267 
268 
269 
270 /**
271  * @brief Solve inverse kinematics and send commands to the controllers.
272  *
273  * @param[in] mpc MPC parameters
274  * @param[in] CoM CoM position
275  * @param[in] control_loop_num number of control loops in future (>= 1).
276  * @param[in,out] wmg WMG
277  */
279  const smpc_parameters &mpc,
280  const smpc::state_com &CoM,
281  const int control_loop_num,
282  WMG &wmg)
283 {
284  // hCoM is constant!
285  nao.setCoM(CoM.x(), CoM.y(), mpc.hCoM);
286 
287 
288  // support foot and swing foot position/orientation
289  wmg.getFeetPositions (
290  control_loop_num * wp.control_sampling_time_ms,
291  nao.left_foot_posture.data(),
292  nao.right_foot_posture.data());
293 
294 
295  // inverse kinematics
296  int iter_num = nao.igm (
298  wp.igm_mu,
299  wp.igm_tol,
300  wp.igm_max_iter);
301  ORUW_LOG_MESSAGE("IGM iterations num: %d\n", iter_num);
302  if (iter_num < 0)
303  {
304  halt("IK does not converge.\n", __FUNCTION__);
305  }
306  int failed_joint = nao.state_model.checkJointBounds();
307  if (failed_joint >= 0)
308  {
309  ORUW_LOG_MESSAGE("Failed joint: %d\n", failed_joint);
310  halt("Joint bounds are violated.\n", __FUNCTION__);
311  }
312 
313 
314  // Set commands
315  try
316  {
317  joint_commands[4][0] = last_dcm_time_ms + control_loop_num * wp.control_sampling_time_ms;
318  for (int i = 0; i < LOWER_JOINTS_NUM; i++)
319  {
320  joint_commands[5][i][0] = nao.state_model.q[i];
321  }
322  dcm_proxy->setAlias(joint_commands);
323  }
324  catch (const AL::ALError &e)
325  {
326  ORUW_LOG_MESSAGE("Cannot set joint angles: %s", e.what());
327  halt("Cannot set joint angles!", __FUNCTION__);
328  }
329 }
330 
331 
332 
333 /**
334  * @brief Correct state and the model based on the sensor data.
335  *
336  * @param[in,out] init_state expected state
337  */
338 void oru_walk::feedbackError (smpc::state_com &init_state)
339 {
340  nao.getCoM (nao.state_sensor, nao.CoM_position);
341 
342 
343  smpc::state_com state_error;
344  state_error.set (
345  init_state.x() - nao.CoM_position[0],
346  init_state.y() - nao.CoM_position[1]);
347 
348  if (state_error.x() > wp.feedback_threshold)
349  {
350  state_error.x() -= wp.feedback_threshold;
351  }
352  else if (state_error.x() < -wp.feedback_threshold)
353  {
354  state_error.x() += wp.feedback_threshold;
355  }
356  else
357  {
358  state_error.x() = 0.0;
359  }
360 
361  if (state_error.y() > wp.feedback_threshold)
362  {
363  state_error.y() -= wp.feedback_threshold;
364  }
365  else if (state_error.y() < -wp.feedback_threshold)
366  {
367  state_error.y() += wp.feedback_threshold;
368  }
369  else
370  {
371  state_error.y() = 0.0;
372  }
373 
374  init_state.x() -= wp.feedback_gain * state_error.x();
375  init_state.y() -= wp.feedback_gain * state_error.y();
376 }
377 
378 
379 
380 /**
381  * @brief Solve the MPC problem.
382  *
383  * @param[in,out] wmg WMG
384  * @param[in,out] mpc MPC parameters
385  *
386  * @return false if there is not enough steps, true otherwise.
387  */
389  WMG &wmg,
390  smpc_parameters &mpc)
391 {
392  oruw_timer timer(__FUNCTION__, wp.loop_time_limit_ms);
393 
394  if (wmg.formPreviewWindow(mpc) == WMG_HALT)
395  {
396  stopWalking("Not enough steps to form preview window. Stopping.");
397  return (false);
398  }
399 
400  //------------------------------------------------------
401  solver->set_parameters (mpc.T, mpc.h, mpc.h[0], mpc.angle, mpc.zref_x, mpc.zref_y, mpc.lb, mpc.ub);
402  solver->form_init_fp (mpc.fp_x, mpc.fp_y, mpc.init_state, mpc.X);
403  solver->solve();
404  solver->get_next_state(mpc.init_state);
405  //------------------------------------------------------
406 
407 
409  if (!timer.check())
410  {
411  halt("Time limit is violated!\n", __FUNCTION__);
412  }
413 
414  return (true);
415 }
416 
417 
418 // ==============================================================================
419 
420 
421 /**
422  * @brief Unregister callback and log a message.
423  *
424  * @param[in] message a message
425  */
426 void oru_walk::stopWalking(const char* message)
427 {
428  ORUW_LOG_MESSAGE("%s", message);
429  qiLogInfo ("module.oru_walk") << message;
430  dcm_callback_connection.disconnect();
431 }
432 
433 
434 
435 /**
436  * @brief Log a message, remove stiffness and die.
437  *
438  * @param[in] message a message
439  * @param[in] function name of the calling function.
440  */
441 void oru_walk::halt(const char *message, const char* function)
442 {
443  stopWalking(message);
444  setStiffness(0.0);
445  throw ALERROR(getName(), function, message);
446 }
447 
448 
449 
450 /**
451  * @brief An interface function that is called remotely to stop
452  * the execution.
453  */
455 {
456  stopWalking ("Stopped by user's request.\n");
458 }
int dcm_loop_counter
Definition: oru_walk.h:140
void setStiffness(const float &)
Set stiffness of joints.
Definition: oru_walk.cpp:151
void dcmCallback()
Wake up walk control thread periodically.
Definition: walking.cpp:95
int last_dcm_time_ms
Definition: oru_walk.h:141
double mpc_ip_tolerance_ext
nao_igm nao
Definition: oru_walk.h:134
bool solveMPCProblem(WMG &, smpc_parameters &)
Solve the MPC problem.
Definition: walking.cpp:388
void walk()
Construct and initialize all necessary classes and register callback function.
Definition: walking.cpp:17
double mpc_gain_acceleration
Log time of existance on destruction. Throw an error, if the given upper limit is not satisfied.
Definition: oruw_timer.h:20
double mpc_gain_position
void walkControl()
A control loop, that is executed in separate thread.
Definition: walking.cpp:173
void readParameters()
Read parameters from configuration file; if the file does not exist, write the default values to it.
bool check()
Checks if the limit is satisfied, logs a message.
Definition: oruw_timer.h:50
int walk_control_thread_priority
double mpc_gain_velocity
smpc::solver * solver
Definition: oru_walk.h:138
void initWalkPattern(WMG &)
Initialize selected walk pattern.
void halt(const char *, const char *)
Log a message, remove stiffness and die.
Definition: walking.cpp:441
ALPtr< DCMProxy > dcm_proxy
Definition: oru_walk.h:143
double ref_joint_angles[LOWER_JOINTS_NUM]
Definition: oru_walk.h:135
void correctNextSupportPosition(WMG &)
The position of the next support foot may change from the targeted, this function moves it to the rig...
Definition: walking.cpp:115
void stopWalkingRemote()
An interface function that is called remotely to stop the execution.
Definition: walking.cpp:454
void solveIKsendCommands(const smpc_parameters &, const smpc::state_com &, const int, WMG &)
Solve inverse kinematics and send commands to the controllers.
Definition: walking.cpp:278
walkParameters wp
Definition: oru_walk.h:137
int * last_dcm_time_ms_ptr
Definition: oru_walk.h:128
double mpc_ip_tolerance_int
boost::condition_variable walk_control_condition
Definition: oru_walk.h:146
ALValue joint_commands
Definition: oru_walk.h:131
#define ORUW_LOG_JOINTS(sensors, actuators)
Definition: oruw_log.h:56
void reset()
Reset timer to the current time.
Definition: oruw_timer.h:39
#define ORUW_LOG_OPEN
Definition: oruw_log.h:51
ProcessSignalConnection dcm_callback_connection
Definition: oru_walk.h:124
double bezier_inclination_1
#define ORUW_LOG_CLOSE
Definition: oruw_log.h:53
void readSensors(jointState &)
Update joint angles.
Definition: walking.cpp:72
ALPtr< ALMemoryFastAccess > access_sensor_values
Definition: oru_walk.h:127
#define ORUW_LOG_COM(mpc, nao)
Definition: oruw_log.h:59
void feedbackError(smpc::state_com &)
Correct state and the model based on the sensor data.
Definition: walking.cpp:338
void initSolver()
Initialize solver.
Definition: walking.cpp:126
boost::mutex walk_control_mutex
Definition: oru_walk.h:147
#define ORUW_LOG_SOLVER_INFO
Definition: oruw_log.h:68
void stopWalking(const char *)
Unregister callback and log a message.
Definition: walking.cpp:426
#define ORUW_LOG_STEPS(wmg)
Definition: oruw_log.h:71
#define ORUW_LOG_MESSAGE(...)
Definition: oruw_log.h:65
double bezier_inclination_2
#define ORUW_LOG_FEET(nao)
Definition: oruw_log.h:62
double feedback_threshold