void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if (nrhs<1) mexErrMsgTxt("usage: ptr = pelvisMotionControlmex(0,robot_obj,alpha,nominal_pelvis_height,Kp,Kd); y=pelvisMotionControlmex(ptr,x)"); if (nlhs<1) mexErrMsgTxt("take at least one output... please."); struct PelvisMotionControlData* pdata; if (mxGetScalar(prhs[0])==0) { // then construct the data object and return pdata = new struct PelvisMotionControlData; // get robot mex model ptr if (!mxIsNumeric(prhs[1]) || mxGetNumberOfElements(prhs[1])!=1) mexErrMsgIdAndTxt("DRC:pelvisMotionControlmex:BadInputs","the second argument should be the robot mex ptr"); memcpy(&(pdata->r),mxGetData(prhs[1]),sizeof(pdata->r)); if (!mxIsNumeric(prhs[2]) || mxGetNumberOfElements(prhs[2])!=1) mexErrMsgIdAndTxt("DRC:pelvisMotionControlmex:BadInputs","the third argument should be alpha"); memcpy(&(pdata->alpha),mxGetPr(prhs[2]),sizeof(pdata->alpha)); if (!mxIsNumeric(prhs[3]) || mxGetNumberOfElements(prhs[3])!=1) mexErrMsgIdAndTxt("DRC:pelvisMotionControlmex:BadInputs","the fourth argument should be nominal_pelvis_height"); memcpy(&(pdata->nominal_pelvis_height),mxGetPr(prhs[3]),sizeof(pdata->nominal_pelvis_height)); if (!mxIsNumeric(prhs[4]) || mxGetM(prhs[4])!=6 || mxGetN(prhs[4])!=1) mexErrMsgIdAndTxt("DRC:pelvisMotionControlmex:BadInputs","the fifth argument should be Kp"); memcpy(&(pdata->Kp),mxGetPr(prhs[4]),sizeof(pdata->Kp)); if (!mxIsNumeric(prhs[5]) || mxGetM(prhs[5])!=6 || mxGetN(prhs[5])!=1) mexErrMsgIdAndTxt("DRC:pelvisMotionControlmex:BadInputs","the sixth argument should be Kd"); memcpy(&(pdata->Kd),mxGetPr(prhs[5]),sizeof(pdata->Kd)); mxClassID cid; if (sizeof(pdata)==4) cid = mxUINT32_CLASS; else if (sizeof(pdata)==8) cid = mxUINT64_CLASS; else mexErrMsgIdAndTxt("Drake:pelvisMotionControlmex:PointerSize","Are you on a 32-bit machine or 64-bit machine??"); pdata->pelvis_height_previous = -1; pdata->pelvis_body_index = pdata->r->findLinkInd("pelvis", 0); pdata->rfoot_body_index = pdata->r->findLinkInd("r_foot", 0); pdata->lfoot_body_index = pdata->r->findLinkInd("l_foot", 0); plhs[0] = mxCreateNumericMatrix(1,1,cid,mxREAL); memcpy(mxGetData(plhs[0]),&pdata,sizeof(pdata)); return; } // first get the ptr back from matlab if (!mxIsNumeric(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1) mexErrMsgIdAndTxt("DRC:pelvisMotionControlmex:BadInputs","the first argument should be the ptr"); memcpy(&pdata,mxGetData(prhs[0]),sizeof(pdata)); int nq = pdata->r->num_dof; int narg = 1; double *q = mxGetPr(prhs[narg++]); double *qd = &q[nq]; Map<VectorXd> qdvec(qd,nq); double lfoot_yaw = mxGetScalar(prhs[narg++]); double rfoot_yaw = mxGetScalar(prhs[narg++]); pdata->r->doKinematics(q,false,qd); // TODO: this must be updated to use quaternions/spatial velocity Vector6d pelvis_pose,rfoot_pose,lfoot_pose; MatrixXd Jpelvis = MatrixXd::Zero(6,pdata->r->num_dof); Vector4d zero = Vector4d::Zero(); zero(3) = 1.0; pdata->r->forwardKin(pdata->pelvis_body_index,zero,1,pelvis_pose); pdata->r->forwardJac(pdata->pelvis_body_index,zero,1,Jpelvis); pdata->r->forwardKin(pdata->rfoot_body_index,zero,1,rfoot_pose); pdata->r->forwardKin(pdata->lfoot_body_index,zero,1,lfoot_pose); if (pdata->pelvis_height_previous<0) { pdata->pelvis_height_previous = pelvis_pose(2); } double min_foot_z = std::min(lfoot_pose(2),rfoot_pose(2)); double mean_foot_yaw = angleAverage(lfoot_yaw,rfoot_yaw); double pelvis_height_desired = pdata->alpha*pdata->pelvis_height_previous + (1.0-pdata->alpha)*(min_foot_z + pdata->nominal_pelvis_height); pdata->pelvis_height_previous = pelvis_height_desired; Vector6d body_des; double nan = std::numeric_limits<double>::quiet_NaN(); body_des << nan,nan,pelvis_height_desired,0,0,mean_foot_yaw; Vector6d error; error.head<3>()= body_des.head<3>()-pelvis_pose.head<3>(); Vector3d error_rpy,pose_rpy,des_rpy; pose_rpy = pelvis_pose.tail<3>(); des_rpy = body_des.tail<3>(); angleDiff(pose_rpy,des_rpy,error_rpy); error.tail(3) = error_rpy; Vector6d body_vdot = (pdata->Kp.array()*error.array()).matrix() - (pdata->Kd.array()*(Jpelvis*qdvec).array()).matrix(); plhs[0] = eigenToMatlab(body_vdot); }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if (nrhs<1) mexErrMsgTxt("usage: ptr = bodyMotionControlmex(0,robot_obj,Kp,Kd,body_index); y=bodyMotionControlmex(ptr,x,body_pose_des,body_v_des,body_vdot_des)"); if (nlhs<1) mexErrMsgTxt("take at least one output... please."); struct BodyMotionControlData* pdata; if (mxGetScalar(prhs[0])==0) { // then construct the data object and return pdata = new struct BodyMotionControlData; // get robot mex model ptr if (!mxIsNumeric(prhs[1]) || mxGetNumberOfElements(prhs[1])!=1) mexErrMsgIdAndTxt("DRC:bodyMotionControlmex:BadInputs","the second argument should be the robot mex ptr"); memcpy(&(pdata->r),mxGetData(prhs[1]),sizeof(pdata->r)); if (!mxIsNumeric(prhs[2]) || mxGetM(prhs[2])!=6 || mxGetN(prhs[2])!=1) mexErrMsgIdAndTxt("DRC:bodyMotionControlmex:BadInputs","the third argument should be Kp"); memcpy(&(pdata->Kp),mxGetPrSafe(prhs[2]),sizeof(pdata->Kp)); if (!mxIsNumeric(prhs[3]) || mxGetM(prhs[3])!=6 || mxGetN(prhs[3])!=1) mexErrMsgIdAndTxt("DRC:bodyMotionControlmex:BadInputs","the fourth argument should be Kd"); memcpy(&(pdata->Kd),mxGetPrSafe(prhs[3]),sizeof(pdata->Kd)); pdata->body_index = (int) mxGetScalar(prhs[4]) -1; mxClassID cid; if (sizeof(pdata)==4) cid = mxUINT32_CLASS; else if (sizeof(pdata)==8) cid = mxUINT64_CLASS; else mexErrMsgIdAndTxt("Drake:bodyMotionControlmex:PointerSize","Are you on a 32-bit machine or 64-bit machine??"); plhs[0] = mxCreateNumericMatrix(1,1,cid,mxREAL); memcpy(mxGetData(plhs[0]),&pdata,sizeof(pdata)); return; } // first get the ptr back from matlab if (!mxIsNumeric(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1) mexErrMsgIdAndTxt("DRC:bodyMotionControlmex:BadInputs","the first argument should be the ptr"); memcpy(&pdata,mxGetData(prhs[0]),sizeof(pdata)); int nq = pdata->r->num_positions; int nv = pdata->r->num_velocities; int narg = 1; Map<VectorXd> q(mxGetPrSafe(prhs[narg]), nq); Map<VectorXd> qd(mxGetPrSafe(prhs[narg++]) + nq, nv); assert(mxGetM(prhs[narg])==6); assert(mxGetN(prhs[narg])==1); Map< Vector6d > body_pose_des(mxGetPrSafe(prhs[narg++])); assert(mxGetM(prhs[narg])==6); assert(mxGetN(prhs[narg])==1); Map< Vector6d > body_v_des(mxGetPrSafe(prhs[narg++])); assert(mxGetM(prhs[narg])==6); assert(mxGetN(prhs[narg])==1); Map< Vector6d > body_vdot_des(mxGetPrSafe(prhs[narg++])); pdata->r->doKinematics(q, qd); // TODO: this must be updated to use quaternions/spatial velocity auto body_pose_gradientvar = pdata->r->forwardKin(Vector3d::Zero().eval(), pdata->body_index, 0, 1, 1); const auto& body_pose = body_pose_gradientvar.value(); const auto& J = body_pose_gradientvar.gradient().value(); Vector6d body_error; body_error.head<3>()= body_pose_des.head<3>()-body_pose.head<3>(); Vector3d error_rpy,pose_rpy,des_rpy; pose_rpy = body_pose.tail<3>(); des_rpy = body_pose_des.tail<3>(); angleDiff(pose_rpy,des_rpy,error_rpy); body_error.tail(3) = error_rpy; Vector6d body_vdot = (pdata->Kp.array()*body_error.array()).matrix() + (pdata->Kd.array()*(body_v_des-J*qd).array()).matrix() + body_vdot_des; plhs[0] = eigenToMatlab(body_vdot); }