青龙源码解析wbc

1. 任务管理:

WBC_walk task:
"static_Contact"; "Roll_Pitch_Yaw_Pz"; "RedundantJoints"; "PxPy"; "SwingLeg"; "HandTrack"; "HandTrackJoints"; "PosRot"

使能:
"static_Contact"; "RedundantJoints"; "SwingLeg"; "HandTrackJoints"; "PosRot"

WBC_stand task:
"static_Contact"; "HandTrackJoints"; "CoMTrack"; "HandTrackJoints"; "HipRPY"; "HeadRP"; "Pz"; "CoMXY_HipRPY"; "Roll_Pitch_Yaw"; "fixedWaist"

使能:
"static_Contact"; "HandTrackJoints"; "CoMXY_HipRPY"; "Pz"; "HeadRP"

2. 任务跟踪:

computeDdq();

walk:
  • static_Contact:
    errX,derrX,ddxDes,dxDes,kp,kd = 0;
    J,dJ读取雅可比,W = 1

  • RedundantJoints:
    errX = Eigen::VectorXd::Zero(5);
    //21-22:头部关节
    //23-25:腰部关节
    errX(0) = 0 - q(21);
    errX(1) = 0 - q(22);
    errX(2) = 0 - q(23);
    errX(3) = 0 - q(24);
    errX(4) = 0 - q(25)
    derrX,ddxDes,dxDes = 0;

  • Roll_Pitch_Yaw_Pz: 姿态高度跟踪任务
    errX(4) = 0;
    errX前3项是期望姿态误差,第4项是位置Z
    errX.block<3, 1>(0, 0) = diffRot(base_rot, desRot);
    errX(3) = base_pos_des(2) - q(2);
    derrX.block<3, 1>(0, 0) = -dq.block<3, 1>(3, 0);
    derrX(3) = 0 - dq(2);
    ddxDes, dxDes = 0;

  • PxPy: 速度
    errX = Eigen::VectorXd::Zero(2);
    errX = des_dq.block(0, 0, 2, 1) * timeStep;
    derrX,ddxDes,dxDes = 0;

  • PosRot: 位置位姿期望无擦痕
    errX = Eigen::VectorXd::Zero(6);
    errX.block(0,0,3,1) = base_pos_des - q.block(0,0,3,1);
    errX.block<3, 1>(3, 0) = diffRot(base_rot, desRot);
    derrX,ddxDes,dxDes = 0;

  • SwingLeg: 误差是末端姿态
    errX = Eigen::VectorXd::Zero(6);
    errX.block<3, 1>(0, 0) = swing_fe_pos_des_W - fe_pos_sw_W;
    desRot = eul2Rot(swing_fe_rpy_des_W(0), swing_fe_rpy_des_W(1), swing_fe_rpy_des_W(2));
    errX.block<3, 1>(3, 0) = diffRot(fe_rot_sw_W, desRot);
    derrX,ddxDes,dxDes = 0;

  • HandTrack: 误差是末端姿态
    先设定末端期望姿态和位置
    errX = Eigen::VectorXd::Zero(12);
    errX.block<3, 1>(0, 0) = hd_l_pos_W_des - hd_l_pos_cur_W;
    errX.block<3, 1>(3, 0) = diffRot(hd_l_rot_cur_W, hd_l_rot_W_des);
    errX.block<3, 1>(6, 0) = hd_r_pos_W_des - hd_r_pos_cur_W;
    diffRot(hd_r_rot_cur_W, hd_r_rot_W_des);

  • HandTrackJoints:误差是末端转关节后的角度误差
    errX=resLeg.jointPosRes.block<14,1>(0,0)-q.block<14,1>(7,0);

stand:
  • static_Contact:
    errX,derrX,ddxDes,dxDes,kp,kd = 0;
    taskCtMap=Eigen::MatrixXd::Zero(3,3);
    taskCtMap(0,0)=0;taskCtMap(1,1)=1;taskCtMap(2,2)=1;
    taskCtMap=fe_l_rot_cur_WtaskCtMapfe_l_rot_cur_W.transpose(); // disable ankle roll joint
    J=Jfe;
    J.block(3,0,3,model_nv)=taskCtMapJ.block(3,0,3,model_nv);
    J.block(9,0,3,model_nv)=taskCtMap
    J.block(9,0,3,model_nv);
    J.block(0,22,12,3).setZero(); // exculde waist joints
    dJ读取雅可比,W = 1

  • HipRPY:
    desRot = eul2Rot(0, 0, 0);
    errX.block<3, 1>(0, 0) = diffRot(hip_link_rot, desRot);
    taskMapRPY = Eigen::MatrixXd::Zero(3, 6);
    taskMapRPY(0, 3) = 1;
    taskMapRPY(1, 4) = 1;
    taskMapRPY(2, 5) = 1;
    J = taskMapRPY * J_hip_link; //髋关节雅可比矩阵
    J.block(0,22,3,3).setZero();
    J.block(0,6,3,14).setZero();

  • Pz:
    errX(0) = base_pos_des(2) - q(2);
    taskMap = Eigen::MatrixXd::Zero(1, 6);
    taskMap(0, 2) = 1;
    J = taskMap * J_base;
    J.block(0,22,1,3).setZero();
    dJ = taskMap * dJ_base;
    dJ.block(0,22,1,3).setZero();

  • CoMTrack:
    errX = Eigen::VectorXd::Zero(2);
    errX = pCoMDes.block(0,0,2,1)-pCoMCur.block(0,0,2,1);
    J = Jcom.block(0,0,2,model_nv);
    J.block(0,6,2,14).setZero();

  • CoMXY_HipRPY: 质心xy跟踪, Hip姿态跟踪
    taskMapRPY = Eigen::MatrixXd::Zero(3, 6);
    taskMapRPY(0, 3) = 1;
    taskMapRPY(1, 4) = 1;
    taskMapRPY(2, 5) = 1;
    errX.block(0,0,2,1) = pCoMDes.block(0,0,2,1)-pCoMCur.block(0,0,2,1);
    errX.block<3, 1>(2, 0) = diffRot(hip_link_rot, desRot);
    J = Eigen::MatrixXd::Zero(5,model_nv);
    J.block(0,0,2,model_nv) = Jcom.block(0,0,2,model_nv);
    J.block(2,0,3,model_nv) = taskMapRPY * J_hip_link;
    J.block(2,22,3,3).setZero(); // exculde waist joints
    J.block(2,6,3,14).setZero(); // exculde arm joints

  • HandTrackJoints: 手部跟踪
    errX=resLeg.jointPosRes.block<14,1>(0,0)-q.block<14,1>(7,0);
    J = Eigen::MatrixXd::Zero(14,model_nv);
    J.block(0,6,14,14)=Eigen::MatrixXd::Identity(14,14);

  • HeadRP: 头部跟踪
    errX = Eigen::VectorXd::Zero(2);
    errX(0)=0-q(21); //头部关节
    errX(1)=base_rpy_cur(1)-q(22); //头部关节
    J = Eigen::MatrixXd::Zero(2,model_nv);
    J(0,20)=1;
    J(1,21)=1;

  • Roll_Pitch_Yaw: 身体姿态跟踪
    errX = diffRot(base_rot, desRot);
    derrX = -dq.block<3, 1>(3, 0);
    taskMap = Eigen::MatrixXd::Zero(3, 6);
    taskMap(0, 3) = 1;
    taskMap(1, 4) = 1;
    taskMap(2, 5) = 1;
    J = taskMap * J_base;
    dJ = taskMap * dJ_base;

  • fixedWaist: 腰部跟踪
    errX = Eigen::VectorXd::Zero(3);
    errX(0) = 0 - q(23);
    errX(1) = 0 - q(24);
    errX(2) = 0 - q(25);
    J = Eigen::MatrixXd::Zero(3, model_nv);
    J(0, 22) = 1;
    J(1, 23) = 1;
    J(2, 24) = 1;

3. 优先级多任务处理:

if (parentId==-1)
{
  taskLib[curId].N=Eigen::MatrixXd::Identity(taskLib[curId].J.cols(),taskLib[curId].J.cols());
  taskLib[curId].Jpre=taskLib[curId].J*taskLib[curId].N;
  taskLib[curId].delta_q=des_delta_q+ pseudoInv_right_weighted(taskLib[curId].Jpre,taskLib[curId].W)*taskLib[curId].errX;
  taskLib[curId].dq=des_dq;
  Eigen::VectorXd ddxcmd= taskLib[curId].ddxDes + taskLib[curId].kp * taskLib[curId].errX+taskLib[curId].kd*taskLib[curId].derrX;
  taskLib[curId].ddq= des_ddq + dyn_pseudoInv(taskLib[curId].Jpre,dyn_M_inv,true) * (ddxcmd - taskLib[curId].dJ * dq);
  std::cout<<taskLib[curId].taskName<<std::endl<<taskLib[curId].delta_q.transpose()<<std::endl;
}
else
{
  taskLib[curId].N=taskLib[parentId].N*
                    (Eigen::MatrixXd::Identity(taskLib[parentId].Jpre.cols(),taskLib[parentId].Jpre.cols())-  
                    pseudoInv_right_weighted(taskLib[parentId].Jpre,taskLib[parentId].W)*taskLib[parentId].Jpre);
  taskLib[curId].Jpre=taskLib[curId].J*taskLib[curId].N;
  taskLib[curId].delta_q=taskLib[parentId].delta_q+ pseudoInv_right_weighted(taskLib[curId].Jpre,taskLib[curId].W)*(taskLib[curId].errX-
  taskLib[curId].J*taskLib[parentId].delta_q);
  taskLib[curId].dq=taskLib[parentId].dq+ pseudoInv_right_weighted(taskLib[curId].Jpre,taskLib[curId].W)*(taskLib[curId].dxDes-
                    taskLib[curId].J*taskLib[parentId].dq);
  Eigen::VectorXd ddxcmd= taskLib[curId].ddxDes + taskLib[curId].kp * taskLib[curId].errX+taskLib[curId].kd*taskLib[curId].derrX;
  taskLib[curId].ddq= taskLib[parentId].ddq + dyn_pseudoInv(taskLib[curId].Jpre,dyn_M_inv,true) *
                                                        (ddxcmd-taskLib[curId].dJ*dq-taskLib[curId].J*taskLib[parentId].ddq);
}

第一次:
\(J_{current, pre} = J_{current}\) 雅可比
\(\Delta q_{current} = \Delta q_{des} + J_{current, pre}^{\dagger}W_{current}^{-1} * e_{current}\) 关节位置增量
\(\dot{q}_{current} = \dot{q}_{des}\) 关节速度
\(\ddot{x}_{cmd} = \ddot{x}_{des} + K_p e_{current} + K_d \dot{e}_{current}\) 任务空间加速度
\(\ddot{q}_{current} = \ddot{q}_{des} + J_{current, pre}^{\dagger} M_{inv}(\ddot{x}_{cmd} - \dot{J}_{current} \dot{q})\) 通过伪逆雅可比矩阵将任务空间的加速度ddx_com转换为关节空间的加速度,同时考虑了惯性矩阵

迭代:
\(N_{current} = N_{parent} * (I - J_{parent, pre}^{\dagger}W_{parent}^{-1} J_{parent,pre})\)
\(J_{current, pre} = J_{current} * N_{current}\) 雅可比
\(\Delta q_{current} = \Delta q_{parent} + J_{current, pre}^{\dagger}W_{current}^{-1} * (e_{current} - J_{current} \Delta q_{parent})\) 关节位置增量
\(\dot{q}_{current} = \dot{q}_{parent} + J_{current, pre}^{\dagger}W_{current}^{-1}(\dot{x}_{des} - J_{current} \dot{q}_{parent})\) 关节速度
\(\ddot{x}_{cmd} = \ddot{x}_{des} + K_p e_{current} + K_d \dot{e}_{current}\) 任务空间加速度
\(\ddot{q}_{current} = \ddot{q}_{parent} + J_{current, pre}^{\dagger} M_{inv}(\ddot{x}_{cmd} - \dot{J}_{current} \dot{q} - J_{current} \ddot{q}_{parent})\)

4. QP问题:

  • \(\ddot{q}^{cmd}:\)由上面优先级多任务处理计算
  • \(f^{MPC}_r:\)由MPC获取
  • \(\delta_f:\)浮动基座加速度松弛变量
  • \(\delta_{f_r}:\)接触力松弛变量
    QP问题就是根据动力学等式约束,来求解这两个最优的松弛变量
    松弛变量求解出来后,\(\ddot{q}\)\(f_r\)也出来了。
    然后根据动力学方程,求解各个关节的力矩:

    \(\tau_j\)即为关节力矩
void WBC_priority::computeTau()
{
  eigen_qp_A1 = Zero(6, 18); //18 means the sum of dims of delta_r and delta_Fr

  St_qpV1 = (37, 6)
  St_qpV1.block<6, 6>(0, 0) = Eigen::MatrixXd::Identity(6, 6);

  //sf是6维浮动动力学选择矩阵
  Sf = Eigen::MatrixXd::Zero(6, 37);
  Sf.block<6, 6>(0, 0) = Eigen::MatrixXd::Identity(6, 6);

  eigen_qp_A1.block<6, 6>(0, 0) = Sf * dyn_M * St_qpV1;
  eigen_qp_A1.block<6, 12>(0, 6) = -Sf * Jfe.transpose(); //Jfe是足末端雅可比 

  Eigen::VectorXd eqRes = Eigen::VectorXd::Zero(6);
  //动力学平衡方程等式约束,这里还没有加上松弛变量,ddq_final_kin由多任务所得关节加速度,Fr_ff是由MPC所得
  eqRes = -Sf * dyn_M * ddq_final_kin - Sf * dyn_Non + Sf * Jfe.transpose() * Fr_ff;
  
  //x是由浮动基座加速度松弛变量(前6维)和接触力松弛变量(后12维)
  // obj: (1/2)x'Hx+x'g
  // s.t. lbA<=Ax<=ubA
  //       lb<=x<=ub
  //H的权重矩阵
  eigen_qp_H.block<6, 6>(0, 0) = Q2 * 2.0 * 1e7;
  eigen_qp_H.block<12, 12>(6, 6) = Q1 * 2.0 * 1e1;
  //由QP问题构造可知,g = 0
  //主要问题由A和lbA,ubA构成,lbA,ubA相等的项为等式约束,不相等的项为不等式约束
  //下面主要分析A和lbA,ubA
  eigen_qp_A_final = Zero(22, 6+12);
  eigen_qp_A_final.block<6, 18>(0, 0) = eigen_qp_A1;
  eigen_qp_A_final.block<16, 18>(6, 0) = eigen_qp_A2;
  eigen_qp_A2.block<16, 12>(0, 6) = W;
  neqRes_low = f_low - W * Fr_ff;
  neqRes_upp = f_upp - W * Fr_ff;
  eigen_qp_lbA.block<6, 1>(0, 0) = eqRes;
  eigen_qp_lbA.block<16, 1>(6, 0) = neqRes_low;
  eigen_qp_ubA.block<6, 1>(0, 0) = eqRes;
  eigen_qp_ubA.block<16, 1>(6, 0) = neqRes_upp;
  res = QP_prob.init(qp_H, qp_g, qp_A, NULL, NULL, qp_lbA, qp_ubA, nWSR, &cpu_time, xOpt_iniGuess);
  
  //获取最优解
  QP_prob.getPrimalSolution(xOpt);
  //加上松弛变量
  eigen_ddq_Opt = ddq_final_kin;
  eigen_ddq_Opt.block<6, 1>(0, 0) += eigen_xOpt.block<6, 1>(0, 0);
  eigen_fr_Opt = Fr_ff + eigen_xOpt.block<12, 1>(6, 0);

  //根据全身动力学计算关节力矩
  tauRes = dyn_M * eigen_ddq_Opt + dyn_Non - Jfe.transpose() * eigen_fr_Opt;
}

posted @ 2024-10-18 14:57  penuel  阅读(37)  评论(0编辑  收藏  举报