Hi all,
I developed a tracking MPC controller for my aerial vehicle from ACADO, and used code generation for porting it to my embeded platform. The overall process was very easy, however I am confused with the following :
1) While using just the toolkit you can define the cost function of the optimal control problem as the follows :
You should have a look at the generated header file, which is typically called 'acado_common.h'.
This header file defines a struct called acadoVariables with all the variables that should be specified in order for the MPC controller to work, including the reference trajectory:
/ The structure containing the user data.
* Via this structure the user "communicates" with the solver code. / typedef struct ACADOvariables_
{
/ Matrix of size: 11 x 8 (row major format)
* Matrix containing 11 differential variable vectors. /
real_t x[ 88 ];
/ Matrix of size: 10 x 2 (row major format)
* Matrix containing 10 control variable vectors. /
real_t u[ 20 ];
/ Column vector of size: 100
* Matrix containing 10 reference/measurement vectors of size 10 for first 10 nodes. /
real_t y[ 100 ];
/ Column vector of size: 8
* Reference/measurement vector for the 11. node. /
real_t yN[ 8 ];
/ Matrix of size: 10 x 10 (row major format) /
real_t W[ 100 ];
/ Matrix of size: 8 x 8 (row major format) /
real_t WN[ 64 ];
/ Column vector of size: 8
* Current state feedback vector. /
real_t x0[ 8 ];
} ACADOvariables;
So the "y" vector contains the reference values over the control horizon, while "yN" are the reference values on the terminal node. Similarly, "W" is the weighting matrix over the control horizon, while "WN" are the weighting values on the terminal node, etc.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for your reply, with that understanding of reference, I generated c code using code generation and wrote a small hexacopter_test program similar to auto generated test.c . In the program , I am trying to simulate the hexacopter to got 1m height which in the program is at :
acadoVariables.y[10] = 1.0
and I run the program with initial values set to zero. But I get the control inputs as zero, not sure why. I have attached the code. Any suggestion would be appreciated.
But you set the value to 1.0 only for one time point then? You should provide a reference trajectory for the full control horizon instead (based on the time discretization that you specified when using the ACADO code generation tool). For example, you could provide the setpoint of 1m for the full MPC control horizon, including the final reference value that is defined in "acadoVariables.yN"
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
//Preparereference//for(i=0;i<N;++i){acadoVariables.y[i * NY +0 ]=0.0;acadoVariables.y[i * NY +1 ]=0.0;acadoVariables.y[i * NY +2 ]=0.0;acadoVariables.y[i * NY +3 ]=0.0;acadoVariables.y[i * NY +4 ]=0.0;acadoVariables.y[i * NY +5 ]=0.0;acadoVariables.y[i * NY +6 ]=0.0;acadoVariables.y[i * NY +7 ]=0.0;acadoVariables.y[i * NY +8 ]=0.0;acadoVariables.y[i * NY +9 ]=0.0;acadoVariables.y[i * NY +10 ]=1.0;acadoVariables.y[i * NY +11 ]=0.0;}acadoVariables.yN[0]=0.0;acadoVariables.yN[1]=0.0;acadoVariables.yN[2]=0.0;acadoVariables.yN[3]=0.0;acadoVariables.yN[4]=0.0;acadoVariables.yN[5]=0.0;acadoVariables.yN[6]=0.0;acadoVariables.yN[7]=0.0;acadoVariables.yN[8]=0.0;acadoVariables.yN[9]=0.0;acadoVariables.yN[10]=1.0;acadoVariables.yN[11]=0.0;//CurrentStateFeedbackcout<<"Initial State Feedback"<<endl;for(i<0;i<NX;++i){acadoVariables.x0[i]=acadoVariables.x[i];cout<<acadoVariables.x0[i];}acado_initializeSolver();//Warm-upSolveracado_preparationStep();for(iter=0;iter<NUM_STEPS;iter++){acado_tic(&t);status=acado_feedbackStep();cout<<"Control : "<<acadoVariables.u[0]<<" "<<acadoVariables.u[1]<<" "<<acadoVariables.u[2]<<" "<<acadoVariables.u[3]<<" "<<acadoVariables.u[4]<<" "<<acadoVariables.u[5]<<endl;t2=acado_toc(&t);//Idealfeedbacksignalcout<<"Feedback Signal "<<endl;for(i=0;i<NX;++i){acadoVariables.x0[i]=acadoVariables.x[NX +i ];cout<<acadoVariables.x0[i]<<endl;}acado_tic(&t);acado_preparationStep();t1=acado_toc(&t);prepSum+=t1;fbdSum+=t2;}
And below is the code used to generate it :
//Introduce the variables
gave a non zero value, to be specific I got status = 31, which basically says theres some error in the qpsolver. I dived further into from where the status is being returned from, I think it is returned from getHessianInverse residing in SolutionAnalysis.cpp .
And the returned value might be from RET_HOTSTART_FAILED .. not sure why
also any idea what status = 31 means,
Any thoughts
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
That is exactly what I wanted to warn you about:
you should probably include the control inputs in the cost function. If you want the control inputs to be penalized only slightly, you can make the weight values (much) smaller than the current values in the Q matrix, but this error from the QP solver will likely go away once you add a nonzero weight value for the control inputs. Note that most QP solvers will have problems with this, given that your current problem formulation is likely to be ill-defined because of non-uniqueness of the optimal control solution caused by the semi-definite Hessian matrix by not having any penalization of control inputs in your control objective.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
acadoVariables..x and acadoVariables.y has the same sequence of variables as
Function h,hN ;
h << p << q << r .....;
However when you use acado_printDifferentialVariables(); it will print them in order they were defined
DifferentialState p,q,r ;
DifferentialState phi,theta,psi ;
DifferentialState x,y,z ;
......
Is that the right understanding ?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hmm, yes and no. acadoVariables.y will indeed have the order of the reference function defined in:
Function h,hN ;
h << p << q << r .....;
However, acadoVariables.x (and therefore also the printing function) follows the order in which you define the state variables and the corresponding differential equations:
Hi all,
I developed a tracking MPC controller for my aerial vehicle from ACADO, and used code generation for porting it to my embeded platform. The overall process was very easy, however I am confused with the following :
1) While using just the toolkit you can define the cost function of the optimal control problem as the follows :
ocp.minimizeLSQ(Q,h,ref)
ocp.minimizeLSQEndTerm(Q,h,ref)
with Q - weighting matrix
h - states
ref - reference for the states
2) While code generation you need to have the cost function without ref i.e.
ocp.minimizeLSQ(Q,h)
ocp.minimizeLSQEndTerm(Q,h)
So I am not sure how to provide reference in the c code obtained from code generation. Any suggestions and recommendations would be appreciated.
Thanking you
Hi,
You should have a look at the generated header file, which is typically called 'acado_common.h'.
This header file defines a struct called acadoVariables with all the variables that should be specified in order for the MPC controller to work, including the reference trajectory:
/ The structure containing the user data.
* Via this structure the user "communicates" with the solver code.
/
typedef struct ACADOvariables_
{
/ Matrix of size: 11 x 8 (row major format)
* Matrix containing 11 differential variable vectors.
/
real_t x[ 88 ];
/ Matrix of size: 10 x 2 (row major format)
* Matrix containing 10 control variable vectors.
/
real_t u[ 20 ];
/ Column vector of size: 100
* Matrix containing 10 reference/measurement vectors of size 10 for first 10 nodes.
/
real_t y[ 100 ];
/ Column vector of size: 8
* Reference/measurement vector for the 11. node.
/
real_t yN[ 8 ];
/ Matrix of size: 10 x 10 (row major format) /
real_t W[ 100 ];
/ Matrix of size: 8 x 8 (row major format) /
real_t WN[ 64 ];
/ Column vector of size: 8
* Current state feedback vector.
/
real_t x0[ 8 ];
} ACADOvariables;
So the "y" vector contains the reference values over the control horizon, while "yN" are the reference values on the terminal node. Similarly, "W" is the weighting matrix over the control horizon, while "WN" are the weighting values on the terminal node, etc.
Hi Rein,
Thank you for your reply, with that understanding of reference, I generated c code using code generation and wrote a small hexacopter_test program similar to auto generated test.c . In the program , I am trying to simulate the hexacopter to got 1m height which in the program is at :
acadoVariables.y[10] = 1.0
and I run the program with initial values set to zero. But I get the control inputs as zero, not sure why. I have attached the code. Any suggestion would be appreciated.
Thanks again
But you set the value to 1.0 only for one time point then? You should provide a reference trajectory for the full control horizon instead (based on the time discretization that you specified when using the ACADO code generation tool). For example, you could provide the setpoint of 1m for the full MPC control horizon, including the final reference value that is defined in "acadoVariables.yN"
So, I do set for y for all the time horizon, code snippet below:
for(i = 0; i<N + 1 ; ++i)
{
acadoVariables.x[i * NX +0 ] = 0.0;
acadoVariables.x[i * NX +1 ] = 0.0;
acadoVariables.x[i * NX +2 ] = 0.0;
acadoVariables.x[i * NX +3 ] = 0.0;
acadoVariables.x[i * NX +4 ] = 0.0;
acadoVariables.x[i * NX +5 ] = 0.0;
acadoVariables.x[i * NX +6 ] = 0.0;
acadoVariables.x[i * NX +7 ] = 0.0;
acadoVariables.x[i * NX +8 ] = 0.0;
acadoVariables.x[i * NX +9 ] = 0.0;
acadoVariables.x[i * NX +10 ] = 0.0;
acadoVariables.x[i * NX +11 ] = 0.0;
}
And below is the code used to generate it :
//Introduce the variables
// Differential Equation
// State Variable and weighting matrix
// Run Opimizer
OCPexport mpc(ocp);
mpc.set(QP_SOLVER, QP_QPOASES);
mpc.set(INTEGRATOR_TYPE, INT_RK4);
mpc.set(GENERATE_TEST_FILE, YES);
mpc.set(GENERATE_MAKE_FILE, YES);
// mpc.printDimensionsQP();
return EXIT_SUCCESS;
So upon closer inspection
status = acado_feedbackStep()
gave a non zero value, to be specific I got status = 31, which basically says theres some error in the qpsolver. I dived further into from where the status is being returned from, I think it is returned from getHessianInverse residing in SolutionAnalysis.cpp .
And the returned value might be from RET_HOTSTART_FAILED .. not sure why
also any idea what status = 31 means,
Any thoughts
That is exactly what I wanted to warn you about:
you should probably include the control inputs in the cost function. If you want the control inputs to be penalized only slightly, you can make the weight values (much) smaller than the current values in the Q matrix, but this error from the QP solver will likely go away once you add a nonzero weight value for the control inputs. Note that most QP solvers will have problems with this, given that your current problem formulation is likely to be ill-defined because of non-uniqueness of the optimal control solution caused by the semi-definite Hessian matrix by not having any penalization of control inputs in your control objective.
Oh fantastic , got it to work thanks a ton...
just a final question :
acadoVariables..x and acadoVariables.y has the same sequence of variables as
Function h,hN ;
h << p << q << r .....;
However when you use acado_printDifferentialVariables(); it will print them in order they were defined
DifferentialState p,q,r ;
DifferentialState phi,theta,psi ;
DifferentialState x,y,z ;
......
Is that the right understanding ?
Great!
Hmm, yes and no. acadoVariables.y will indeed have the order of the reference function defined in:
However, acadoVariables.x (and therefore also the printing function) follows the order in which you define the state variables and the corresponding differential equations:
ok , Thanks for your help again..