Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007 #include "lyap_control/controller.h"
00008
00009
00010 int main(int argc, char **argv)
00011 {
00012 ROS_INFO("Check the num. of states and num. of inputs.");
00013 ROS_INFO("These can be adjusted in 'controller_msg.msg' and 'plant_msg.msg' files.");
00014 ROS_INFO("num_states: %i num_inputs: %i",num_states,num_inputs);
00015 ROS_INFO(" ");
00016 ROS_INFO("Also check the parameters of the controller at the top of lyap_control/include/controller.h");
00017
00018
00019 ros::init(argc, argv, "controller");
00020 ros::NodeHandle controller_node;
00021 ros::Publisher chatter_pub = controller_node.advertise<lyap_control::controller_msg>("control_effort", 1);
00022 ros::Subscriber sub = controller_node.subscribe("state", 1, chatterCallback );
00023
00024
00025 while (ros::ok())
00026 {
00027 ros::spinOnce();
00028
00029
00030 chatter_pub.publish(u_msg);
00031 }
00032
00033 return 0;
00034 }
00035
00036
00038
00039
00041 void chatterCallback(const lyap_control::plant_msg& msg)
00042 {
00043
00044
00045 if ( first_callback )
00046 {
00047 initial_error_check(msg);
00048 }
00049
00050
00051 for (int i=0; i<num_states; i++)
00052 {
00053 x[i]=msg.x[i];
00054 setpoint[i] = msg.setpoint[i];
00055 }
00056
00057
00058 boost::numeric::ublas::matrix<double> dx_dot_du (num_inputs, num_states);
00059 ublas_vector open_loop_dx_dt(x);
00060 calculate_dx_dot_du( dx_dot_du, open_loop_dx_dt );
00061
00062
00063
00064 ublas_vector D(num_inputs);
00065
00066 D.clear();
00067
00068 for (int i=0; i<num_inputs; i++)
00069 for (int j=0; j<num_states; j++)
00070
00071 D[i] = D[i]+( msg.x[j]-setpoint[j] )*dx_dot_du(i,j);
00072
00073
00074
00075 double V_dot_target;
00076 calculate_V_and_damping(V_dot_target);
00077
00078
00079 calculate_u(D, open_loop_dx_dt, V_dot_target, dx_dot_du);
00080
00081
00082 for (int i=0; i<num_inputs; i++)
00083 {
00084 if ( u[i] < low_saturation_limit[i] )
00085 {
00086 u[i] = low_saturation_limit[i];
00087 }
00088 if ( u[i] > high_saturation_limit[i] )
00089 {
00090 u[i] = high_saturation_limit[i];
00091 }
00092 }
00093
00094
00095 for (int i=0; i<num_inputs; i++)
00096 u_msg.u[i] = u[i];
00097
00098
00099 }
00100
00102
00104 void initial_error_check(const lyap_control::plant_msg& msg)
00105 {
00106
00107 V_dot_target_initial = pow(-10, V_dot_target_initial_dB/(-20.0));
00108
00109 if ( V_dot_target_initial >= 0 )
00110 {
00111 ROS_ERROR("V_dot_target_initial must be negative. Change it in controller_parameters.h.");
00112 ros::shutdown();
00113 }
00114
00115 if ( (sizeof(high_saturation_limit)+sizeof(low_saturation_limit)) / sizeof(*high_saturation_limit) != 2*num_inputs )
00116 {
00117 ROS_ERROR("Check your saturation limit definitions. There are too many or too few values in one of the arrays. They must match the # of inputs to the system.");
00118 ros::shutdown();
00119 }
00120
00121 for (int i=0; i<num_inputs; i++)
00122 if ( low_saturation_limit[i] >= high_saturation_limit[i] )
00123 {
00124 ROS_ERROR("The 'low saturation limit' is higher than 'high saturation limit.' Change them in controller_parameters.h.");
00125 ros::shutdown();
00126 };
00127
00128 if ( msg.setpoint.size() != num_states )
00129 {
00130 ROS_ERROR("The published setpoint's length does not equal # of states. Check the data which is published by the plant.");
00131 ros::shutdown();
00132 }
00133 }
00134
00136
00138 void calculate_dx_dot_du( boost::numeric::ublas::matrix<double> &dx_dot_du, ublas_vector &open_loop_dx_dt )
00139 {
00141
00143
00144
00145 u.clear();
00146
00147 model_definition(x,open_loop_dx_dt,t);
00148
00150
00152
00153 ublas_vector closed_loop_dx_dt(num_states);
00154
00155 for ( int i=0; i<num_inputs; i++ )
00156 {
00157 u.clear();
00158 u[i] = 1.0;
00159 model_definition(x,closed_loop_dx_dt,t);
00160 for ( int j=0; j<num_states; j++ )
00161 {
00162 dx_dot_du(i,j) = closed_loop_dx_dt[j]-open_loop_dx_dt[j];
00163 }
00164 }
00165 }
00166
00168
00170 void calculate_V_and_damping(double &V_dot_target)
00171 {
00172
00173 V = 0.5*inner_prod(x-setpoint,x-setpoint);
00174 ROS_INFO("V: %f", V);
00175
00176 if ( first_callback )
00177 {
00178 first_callback=0;
00179 V_initial = V;
00180 }
00181
00182
00183 V_dot_target = pow((V/V_initial),2.0)*V_dot_target_initial;
00184 }
00185
00187
00189 void calculate_u(ublas_vector &D, ublas_vector &open_loop_dx_dt, const double &V_dot_target, boost::numeric::ublas::matrix<double> &dx_dot_du)
00190 {
00191 u.clear();
00192
00193
00194
00195
00196 int largest_D_index = index_norm_inf(D);
00197
00198 if ( fabs(D[largest_D_index]) > switching_threshold )
00199 {
00200 ublas_vector P = element_prod(x-setpoint,open_loop_dx_dt);
00201
00202
00203 if ( fabs( D[largest_D_index] + ( sum( element_prod(D,D) ) - pow(D[largest_D_index],2.0) )/D[largest_D_index]) > 0.0001 )
00204 u(largest_D_index) = D[largest_D_index]*(V_dot_target-sum(P)) /
00205 sum( element_prod(D,D) );
00206
00207
00208 for ( int i=0; i<num_inputs; i++ )
00209 if ( i != largest_D_index )
00210 {
00211
00212
00213 u[i] = u[largest_D_index]*D[i]/D[largest_D_index];
00214
00215 }
00216 }
00217
00218 else
00219 {
00220
00221
00222
00223 ublas_vector dV2_dx = (x-setpoint)*(0.9+0.1*tanh(g)+0.05*sum( element_prod(x-setpoint,x-setpoint) )*pow(cosh(g),-2));
00224
00225
00226 dV2_dx[0] = (x[0]-setpoint[0])*(0.9+0.1*tanh(g))+
00227 0.05*sum(element_prod(x-setpoint,x-setpoint))*(pow((x[0]-setpoint[0]),-1)*tanh(g)+(x[0]-setpoint[0])*pow(cosh(g),-2));
00228
00229
00230
00231
00232
00233 ublas_vector P_star = element_prod(dV2_dx, open_loop_dx_dt);
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 ublas_vector D_star(num_inputs);
00244
00245 for (int i=0; i<num_inputs-1; i++)
00246 for (int j=0; j<num_inputs-1; j++)
00247 D_star[i] = D_star[i]+dV2_dx[j]*dx_dot_du(i,j);
00248
00249
00250
00251
00252
00253
00254
00255 u[0] = (V_dot_target-sum(P_star)) /
00256 ( D_star[0] + (sum( element_prod(D_star,D_star) )-pow(D_star[0],2)) / D_star[0] );
00257
00258
00259
00260
00261
00262
00263
00264 for (int i=1; i<num_inputs; i++)
00265 {
00266 u[i] = u[0]*D_star[i]/D_star(0);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276 for (int i=0; i<num_inputs; i++)
00277 {
00278 if ( (boost::math::isnan)(u[i]) )
00279 {
00280 u.clear();
00281
00282 break;
00283 }
00284 }
00285 }
00286 }