int main() { USING_NAMESPACE_ACADO; // INTRODUCE THE VARIABLES: // ------------------------- DifferentialState x,y,z, vx,vy,vz, phi,theta,psi, p,q,r;// u1,u2,u3,u4; // x, y, z : position // vx, vy, vz : linear velocity // phi, theta, psi : orientation (Yaw-Pitch-Roll = Euler(3,2,1)) // p, q, r : angular velocity // u1, u2, u3, u4 : velocity of the propellers Control u1,u2,u3,u4; // vu1, vu2, vu3, vu4 : derivative of u1, u2, u3, u4 // Quad constants const double c = 0.00001; const double Cf = 0.00065; const double d = 0.250; const double Jx = 0.018; const double Jy = 0.018; const double Jz = 0.026; const double m = 0.9; const double g = 9.81; // DEFINE A DIFFERENTIAL EQUATION: // ------------------------------- DifferentialEquation f; f << dot(x) == vx; f << dot(y) == vy; f << dot(z) == vz; f << dot(vx) == Cf*(u1*u1+u2*u2+u3*u3+u4*u4)*sin(theta)/m; f << dot(vy) == -Cf*(u1*u1+u2*u2+u3*u3+u4*u4)*sin(psi)*cos(theta)/m; f << dot(vz) == Cf*(u1*u1+u2*u2+u3*u3+u4*u4)*cos(psi)*cos(theta)/m - g; f << dot(phi) == -cos(phi)*tan(theta)*p+sin(phi)*tan(theta)*q+r; f << dot(theta) == sin(phi)*p+cos(phi)*q; f << dot(psi) == cos(phi)/cos(theta)*p-sin(phi)/cos(theta)*q; f << dot(p) == (d*Cf*(u1*u1-u2*u2)+(Jy-Jz)*q*r)/Jx; f << dot(q) == (d*Cf*(u4*u4-u3*u3)+(Jz-Jx)*p*r)/Jy; f << dot(r) == (c*(u1*u1+u2*u2-u3*u3-u4*u4)+(Jx-Jy)*p*q)/Jz; /* f << dot(u1) == vu1; f << dot(u2) == vu2; f << dot(u3) == vu3; f << dot(u4) == vu4; */ // SET UP THE SIMULATED PROCESS: // ----------------------------- DynamicSystem dynamicSystem(f,OutputFcn{}); Process process(dynamicSystem,INT_RK45); // DEFINE LEAST SQUARE FUNCTION: // ----------------------------- Function h; h << vx << vy << vz; // h << vu1 << vu2 << vu3 << vu4; h << u1 << u2 << u3 << u4; h << p << q << r; // LSQ coefficient matrix DMatrix Q(10,10); Q(0,0) = Q(1,1) = Q(2,2) = 1e-1; Q(3,3) = Q(4,4) = Q(5,5) = Q(6,6) = 1e-9; Q(7,7) = Q(8,8) = Q(9,9) = 1e-1; // Reference DVector refVec(10); refVec.setZero(10); // DEFINE AN OPTIMAL CONTROL PROBLEM: // ---------------------------------- OCP ocp(0., 1., 4); ocp.minimizeLSQ(Q, h, refVec); // Constraints on the velocity of each propeller ocp.subjectTo(f); ocp.subjectTo(16 <= u1 <= 95); ocp.subjectTo(16 <= u2 <= 95); ocp.subjectTo(16 <= u3 <= 95); ocp.subjectTo(16 <= u4 <= 95); // Command constraints // Constraints on the acceleration of each propeller /* ocp.subjectTo(-200 <= vu1 <= 200); ocp.subjectTo(-200 <= vu2 <= 200); ocp.subjectTo(-200 <= vu3 <= 200); ocp.subjectTo(-200 <= vu4 <= 200); */ // Constraint to avoid singularity ocp.subjectTo(-1. <= theta <= 1.); // Adding roof, floor and walls constraints /* ocp.subjectTo(-9.7 <= x <= 9.7); ocp.subjectTo(-9.7 <= y <= 9.7); ocp.subjectTo(.3 <= z <= 9.7); */ // Loading cylindrical obstacles from XML EnvironmentParser parser(PIE_SOURCE_DIR"/data/envsave.xml"); auto cylinders = parser.readData(); for (Ecylinder c : cylinders) { ocp.subjectTo(pow(c.radius + 1,2) <= ( pow((y-c.y1)*(c.z2-c.z1)-(c.y2-c.y1)*(z-c.z1),2) + pow((z-c.z1)*(c.x2-c.x1)-(c.z2-c.z1)*(x-c.x1),2) + pow((x-c.x1)*(c.y2-c.y1)-(c.x2-c.x1)*(y-c.y1),2) ) / ( pow(c.x2-c.x1,2) + pow(c.y2-c.y1,2) + pow(c.z2-c.z1,2) ) ); } // SET UP THE MPC CONTROLLER: // -------------------------- RealTimeAlgorithm alg(ocp); alg.set(INTEGRATOR_TYPE, INT_RK45); alg.set(MAX_NUM_ITERATIONS,1); alg.set(PRINT_COPYRIGHT, false); alg.set(DISCRETIZATION_TYPE, SINGLE_SHOOTING); Controller controller(alg); // SETTING UP THE SIMULATION ENVIRONMENT: // -------------------------------------- DVector X(12), U(4), U0(4); X.setZero(); X(2) = 4.; // X(12) = X(13) = X(14) = X(15) = 58.; U.setZero(); U0.setZero(); controller.init(0., X); process.init(0., X, U); // VariablesGrid graph; VariablesGrid Y; Y.setZero(); // END OF ACADO SOLVER SETUP // ------------------------- // Initialise input from keyboard Input input(false); // Gepetto viewer over corba Viewer viewer; viewer.createEnvironment(cylinders); viewer.createDrone(PIE_SOURCE_DIR"/data/quadrotor_base.stl"); double t = 0; std::clock_t previousTime; previousTime = std::clock(); auto refInput = input.getReference(); DVector LastRefVec(10); LastRefVec.setZero(); while(true) { // getting reference from input and passing it to the algorithm refInput = input.getReference(); if (abs(refInput[0]-LastRefVec(0))>1.) { if (refInput[0]>LastRefVec(0)) { refInput[0] = LastRefVec(0)+1.;} else {refInput[0] = LastRefVec(0)-1.;} } if (abs(refInput[1]-LastRefVec(1))>1.) { if (refInput[1]>LastRefVec(1)) { refInput[1] = LastRefVec(1)+1.;} else {refInput[1] = LastRefVec(1)-1.;} } if (abs(refInput[0]-LastRefVec(0))>1.) { if (refInput[2]>LastRefVec(2)) { refInput[2] = LastRefVec(2)+1.;} else {refInput[2] = LastRefVec(2)-1.;} } double refT[10] = {refInput[0], refInput[1], refInput[2], 0., 0., 0., 0., 0., 0., 0.}; DVector refVec(10, refT); VariablesGrid referenceVG (refVec, Grid{t, t+1., 2}); referenceVG.setVector(0, LastRefVec); alg.setReference(referenceVG); LastRefVec = refVec; // get state vector process.getY(Y); X = Y.getLastVector(); // move the drone and draw the arrow // viewer takes roll-pitch-yaw but drone equations are in yaw-pitch-roll viewer.moveDrone(X(0), X(1), X(2), X(8), X(7), X(6)); //viewer.setArrow((refInput[0]>0) - (refInput[0]<0), (refInput[1]>0) - (refInput[1]<0), (refInput[2]>0) - (refInput[2]<0)); viewer.setArrow(refInput[0], refInput[1], refInput[2]); // MPC step // compute the command bool success = controller.step(t, X); if (success != 0) { std::cout << "controller failed " << std::endl; return 1; } controller.getU(U); // simulate the drone std::clock_t currentTime = std::clock(); double dt = (double)(currentTime - previousTime) / (double)CLOCKS_PER_SEC; process.step(t,t+dt,U); t += dt; // get the new state vector process.getY(Y); X = Y.getLastVector(); // move the drone to it's new position // viewer takes roll-pitch-yaw but drone equations are in yaw-pitch-roll viewer.moveDrone(X(0), X(1), X(2), X(8), X(7), X(6)); previousTime = currentTime; // graph.addVector(X,t); } // draw every variable into a graph. Useful for debug // GnuplotWindow window; // window.addSubplot(graph(0), "x"); // window.addSubplot(graph(1), "y"); // window.addSubplot(graph(2), "z"); // window.addSubplot(graph(3), "vx"); // window.addSubplot(graph(4), "vy"); // window.addSubplot(graph(5), "vz"); // window.addSubplot(graph(6), "phi"); // window.addSubplot(graph(7), "theta"); // window.addSubplot(graph(8), "psi"); // window.addSubplot(graph(9), "p"); // window.addSubplot(graph(10), "q"); // window.addSubplot(graph(11), "r"); // window.addSubplot(graph(12), "u1"); // window.addSubplot(graph(13), "u2"); // window.addSubplot(graph(14), "u3"); // window.addSubplot(graph(15), "u4"); // window.plot(); return 0; }