00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <graft/GraftUKFAttitude.h>
00035 #include <ros/console.h>
00036
00037 GraftUKFAttitude::GraftUKFAttitude(){
00038 graft_state_.setZero();
00039 graft_state_(0,0) = 1.0;
00040 graft_control_.setZero();
00041 graft_covariance_.setIdentity();
00042 Q_.setZero();
00043 }
00044
00045 GraftUKFAttitude::~GraftUKFAttitude(){
00046
00047 }
00048
00049 VectorXd verticalConcatenate(VectorXd& m, VectorXd& n){
00050 if(m.rows() == 0){
00051 return n;
00052 }
00053 VectorXd out;
00054 out.resize(m.rows()+n.rows(), m.cols());
00055 out << m,n;
00056 return out;
00057 }
00058
00059 MatrixXd verticalConcatenate(MatrixXd& m, MatrixXd& n){
00060 if(m.rows() == 0){
00061 return n;
00062 }
00063 MatrixXd out;
00064 out.resize(m.rows()+n.rows(), m.cols());
00065 out << m,n;
00066 return out;
00067 }
00068
00069 MatrixXd matrixSqrt(MatrixXd matrix){
00070
00071 return Eigen::LLT<Eigen::MatrixXd>(matrix).matrixL();
00072 }
00073
00074 std::vector<MatrixXd > generateSigmaPoints(MatrixXd state, MatrixXd covariance, double lambda){
00075 std::vector<MatrixXd > out;
00076
00077 double gamma = std::sqrt((state.rows()+lambda));
00078 MatrixXd sig_sqrt = gamma*matrixSqrt(covariance);
00079
00080
00081 out.push_back(state);
00082
00083
00084 for(size_t i = 1; i <= state.rows(); i++){
00085 out.push_back(state + sig_sqrt.col(i-1));
00086 }
00087
00088
00089 for(size_t i = state.rows() + 1; i <= 2*state.rows(); i++){
00090 out.push_back(state - sig_sqrt.col(i-(state.rows()+1)));
00091 }
00092
00093 return out;
00094 }
00095
00096 MatrixXd meanFromSigmaPoints(std::vector<MatrixXd >& sigma_points, double n, double lambda){
00097 double weight_zero = lambda / (n + lambda);
00098 MatrixXd out = weight_zero * sigma_points[0];
00099 double weight_i = 1.0/(2*(n + lambda));
00100 for(size_t i = 1; i <= 2*n; i++){
00101 out = out + weight_i * sigma_points[i];
00102 }
00103 return out;
00104 }
00105
00107 MatrixXd covarianceFromSigmaPoints(std::vector<MatrixXd >& sigma_points, MatrixXd& mean, MatrixXd process_noise, double n, double alpha, double beta, double lambda){
00108 double cov_weight_zero = lambda / (n + lambda) + (1 - alpha*alpha + beta);
00109 MatrixXd out = cov_weight_zero * (sigma_points[0] - mean) * (sigma_points[0] - mean).transpose();
00110 double weight_i = 1.0/(2*(n + lambda));
00111 for(size_t i = 1; i <= 2*n; i++){
00112 out = out + weight_i * (sigma_points[i] - mean) * (sigma_points[i] - mean).transpose();
00113 }
00114 return out+process_noise;
00115 }
00116
00117 MatrixXd crossCovariance(std::vector<MatrixXd >& sigma_points, MatrixXd& mean, std::vector<MatrixXd >& meas_sigma_points, MatrixXd& meas_mean, double alpha, double beta, double lambda){
00118 double n = sigma_points[0].rows();
00119 double cov_weight_zero = lambda / (n + lambda) + (1 - alpha*alpha + beta);
00120 MatrixXd out = cov_weight_zero * (sigma_points[0] - mean) * (meas_sigma_points[0] - meas_mean).transpose();
00121 double weight_i = 1.0/(2*(n + lambda));
00122 for(size_t i = 1; i <= 2*n; i++){
00123 out = out + weight_i * (sigma_points[i] - mean) * (meas_sigma_points[i] - meas_mean).transpose();
00124 }
00125 return out;
00126 }
00127
00128 Matrix<double, 4, 4> quaternionUpdateMatrix(const double wx, const double wy, const double wz){
00129 Matrix<double, 4, 4> out;
00130 out << 0, wx, wy, wz,
00131 -wx, 0, -wz, wy,
00132 -wy, wz, 0, -wx,
00133 -wz, -wy, wx, 0;
00134 return out;
00135 }
00136
00137 Matrix<double, 4, 1> unitQuaternion(const Matrix<double, 4, 1>& q){
00138 double q_mag = std::sqrt(q(0)*q(0) + q(1)*q(1) + q(2)*q(2) + q(3)*q(3));
00139 return q / q_mag;
00140 }
00141
00142 Matrix<double, 4, 1> updatedQuaternion(const Matrix<double, 4, 1>& q, const double wx, const double wy, const double wz, double dt){
00143 Matrix<double, 4, 1> out;
00144 Matrix<double, 4, 4> I = Matrix<double, 4, 4>::Identity();
00145 double s = 1.0/2.0 * std::sqrt(wx*wx*dt*dt + wy*wy*dt*dt + wz*wz*dt*dt);
00146 double k = 0.0;
00147 double q_mag = std::sqrt(q(0)*q(0) + q(1)*q(1) + q(2)*q(2) + q(3)*q(3));
00148 double err = 1.0 - q_mag*q_mag;
00149
00150 double correction_factor = 1 - 1.0/2.0*s*s + 1.0/24.0*s*s*s*s + k * dt * err;
00151 MatrixXd correction = I*(correction_factor);
00152 double update_factor = 1.0/2.0*dt*(1.0 - 1.0/6.0*s*s + 1.0/120.0*s*s*s*s);
00153 Matrix<double, 4, 4> quaterion_update_matrix = quaternionUpdateMatrix(wx, wy, wz);
00154 MatrixXd update = update_factor*quaterion_update_matrix;
00155 out = (correction-update)*q;
00156
00157
00158 double out_mag = std::sqrt(out(0)*out(0) + out(1)*out(1) + out(2)*out(2) + out(3)*out(3));
00159 double out_err = 1.0 - out_mag*out_mag;
00160
00161 return out;
00162 }
00163
00164 MatrixXd GraftUKFAttitude::f(MatrixXd x, double dt){
00165 Matrix<double, SIZE, 1> out;
00166 out.setZero();
00167 Matrix<double, 4, 1> new_q = updatedQuaternion(x.block(0, 0, 4, 1), x(4), x(5), x(6), dt);
00168 out.block(0, 0, 4, 1) = new_q;
00169 out(4) = x(4);
00170 out(5) = x(5);
00171 out(6) = x(6);
00172 return out;
00173 }
00174
00175 graft::GraftState::ConstPtr stateMsgFromMatrix(const MatrixXd& state){
00176 graft::GraftState::Ptr out(new graft::GraftState());
00177 out->pose.orientation.w = state(0);
00178 out->pose.orientation.x = state(1);
00179 out->pose.orientation.y = state(2);
00180 out->pose.orientation.z = state(3);
00181 out->twist.angular.x = state(4);
00182 out->twist.angular.y = state(5);
00183 out->twist.angular.z = state(6);
00184 return out;
00185 }
00186
00187 std::vector<MatrixXd > GraftUKFAttitude::predict_sigma_points(std::vector<MatrixXd >& sigma_points, double dt){
00188 std::vector<MatrixXd > out;
00189 for(size_t i = 0; i < sigma_points.size(); i++){
00190 out.push_back(f(sigma_points[i], dt));
00191 }
00192 return out;
00193 }
00194
00195 graft::GraftStatePtr GraftUKFAttitude::getMessageFromState(){
00196 return GraftUKFAttitude::getMessageFromState(graft_state_, graft_covariance_);
00197 }
00198
00199 graft::GraftStatePtr GraftUKFAttitude::getMessageFromState(Matrix<double, SIZE, 1>& state, Matrix<double, SIZE, SIZE>& covariance){
00200 graft::GraftStatePtr msg(new graft::GraftState());
00201 msg->pose.orientation.w = state(0);
00202 msg->pose.orientation.x = state(1);
00203 msg->pose.orientation.y = state(2);
00204 msg->pose.orientation.z = state(3);
00205 msg->twist.angular.x = state(4);
00206 msg->twist.angular.y = state(5);
00207 msg->twist.angular.z = state(6);
00208
00209 for(size_t i = 0; i < SIZE*SIZE; i++){
00210 msg->covariance[i] = covariance(i);
00211 }
00212 return msg;
00213 }
00214
00215 VectorXd addElementToVector(const VectorXd& vec, const double element){
00216 if(vec.size() == 0){
00217 VectorXd out(1);
00218 out(0) = element;
00219 return out;
00220 }
00221 VectorXd out(vec.size() + 1);
00222 out << vec, element;
00223 return out;
00224 }
00225
00226 MatrixXd addElementToColumnMatrix(const MatrixXd& mat, const double element){
00227 MatrixXd out(mat.rows() + 1, 1);
00228 MatrixXd small(1, 1);
00229 small(0,0) = element;
00230 if(mat.rows() == 0){
00231 return small;
00232 }
00233 out << mat, small;
00234 return out;
00235 }
00236
00237 geometry_msgs::Vector3 normalized_acceleration(const geometry_msgs::Vector3& accel){
00238 geometry_msgs::Vector3 out;
00239 double mag = std::sqrt(accel.x*accel.x + accel.y*accel.y + accel.z*accel.z);
00240 out.x = accel.x / mag;
00241 out.y = accel.y / mag;
00242 out.z = accel.z / mag;
00243 return out;
00244 }
00245
00246
00247 VectorXd getMeasurements(const std::vector<boost::shared_ptr<GraftSensor> >& topics, const std::vector<MatrixXd>& predicted_sigma_points, std::vector<MatrixXd>& output_measurement_sigmas, MatrixXd& output_innovation_covariance){
00248 VectorXd actual_measurement;
00249 output_measurement_sigmas.clear();
00250 VectorXd innovation_covariance_diagonal;
00251 innovation_covariance_diagonal.resize(0);
00252
00253 std::vector<graft::GraftState::ConstPtr> predicted_sigma_msgs;
00254 for(size_t i = 0; i < predicted_sigma_points.size(); i++){
00255 predicted_sigma_msgs.push_back(stateMsgFromMatrix(predicted_sigma_points[i]));
00256 output_measurement_sigmas.push_back(MatrixXd());
00257 }
00258
00259
00260
00261 for(size_t i = 0; i < topics.size(); i++){
00262
00263 graft::GraftSensorResidual::ConstPtr meas = topics[i]->z();
00264
00265 std::vector<graft::GraftSensorResidual::ConstPtr> residuals_msgs;
00266 for(size_t j = 0; j < predicted_sigma_msgs.size(); j++){
00267 graft::GraftSensorResidual::Ptr msg = topics[i]->h(*predicted_sigma_msgs[j]);
00268 residuals_msgs.push_back(msg);
00269
00270 }
00271
00272 if(meas == NULL){
00273 continue;
00274 }
00275
00276 if(meas->twist_covariance[21] > 1e-20){
00277 actual_measurement = addElementToVector(actual_measurement, meas->twist.angular.x);
00278 innovation_covariance_diagonal = addElementToVector(innovation_covariance_diagonal, meas->twist_covariance[21]);
00279 for(size_t j = 0; j < residuals_msgs.size(); j++){
00280 output_measurement_sigmas[j] = addElementToColumnMatrix(output_measurement_sigmas[j], residuals_msgs[j]->twist.angular.x);
00281 }
00282 }
00283
00284 if(meas->twist_covariance[28] > 1e-20){
00285 actual_measurement = addElementToVector(actual_measurement, meas->twist.angular.y);
00286 innovation_covariance_diagonal = addElementToVector(innovation_covariance_diagonal, meas->twist_covariance[28]);
00287 for(size_t j = 0; j < residuals_msgs.size(); j++){
00288 output_measurement_sigmas[j] = addElementToColumnMatrix(output_measurement_sigmas[j], residuals_msgs[j]->twist.angular.y);
00289 }
00290 }
00291
00292 if(meas->twist_covariance[35] > 1e-20){
00293 actual_measurement = addElementToVector(actual_measurement, meas->twist.angular.z);
00294 innovation_covariance_diagonal = addElementToVector(innovation_covariance_diagonal, meas->twist_covariance[35]);
00295 for(size_t j = 0; j < residuals_msgs.size(); j++){
00296 output_measurement_sigmas[j] = addElementToColumnMatrix(output_measurement_sigmas[j], residuals_msgs[j]->twist.angular.z);
00297 }
00298 }
00299
00300 if(meas->accel_covariance[0] > 1e-20 && meas->accel_covariance[4] > 1e-20 && meas->accel_covariance[8] > 1e-20){
00301 geometry_msgs::Vector3 accel_meas_norm = normalized_acceleration(meas->accel);
00302 actual_measurement = addElementToVector(actual_measurement, accel_meas_norm.x);
00303 actual_measurement = addElementToVector(actual_measurement, accel_meas_norm.y);
00304 actual_measurement = addElementToVector(actual_measurement, accel_meas_norm.z);
00305 innovation_covariance_diagonal = addElementToVector(innovation_covariance_diagonal, meas->accel_covariance[0]);
00306 innovation_covariance_diagonal = addElementToVector(innovation_covariance_diagonal, meas->accel_covariance[4]);
00307 innovation_covariance_diagonal = addElementToVector(innovation_covariance_diagonal, meas->accel_covariance[8]);
00308 for(size_t j = 0; j < residuals_msgs.size(); j++){
00309 geometry_msgs::Vector3 res_meas_norm = normalized_acceleration(residuals_msgs[j]->accel);
00310 output_measurement_sigmas[j] = addElementToColumnMatrix(output_measurement_sigmas[j], res_meas_norm.x);
00311 output_measurement_sigmas[j] = addElementToColumnMatrix(output_measurement_sigmas[j], res_meas_norm.y);
00312 output_measurement_sigmas[j] = addElementToColumnMatrix(output_measurement_sigmas[j], res_meas_norm.z);
00313 }
00314 }
00315 }
00316
00317
00318 output_innovation_covariance = innovation_covariance_diagonal.asDiagonal();
00319
00320 return actual_measurement;
00321 }
00322
00323 void clearMessages(std::vector<boost::shared_ptr<GraftSensor> >& topics){
00324 for(size_t i = 0; i < topics.size(); i++){
00325 topics[i]->clearMessage();
00326 }
00327 }
00328
00329 double GraftUKFAttitude::predictAndUpdate(){
00330 if(topics_.size() == 0 || topics_[0] == NULL){
00331 return 0;
00332 }
00333 ros::Time t = ros::Time::now();
00334 double dt = (t - last_update_time_).toSec();
00335 if(last_update_time_.toSec() < 0.0001){
00336 ROS_WARN("Negative dt, skipping update.");
00337 last_update_time_ = t;
00338 return 0.0;
00339 }
00340 last_update_time_ = t;
00341
00342
00343 double lambda = alpha_*alpha_*(SIZE + kappa_) - SIZE;
00344 std::vector<MatrixXd > previous_sigma_points = generateSigmaPoints(graft_state_, graft_covariance_, lambda);
00345 std::vector<MatrixXd > predicted_sigma_points = predict_sigma_points(previous_sigma_points, dt);
00346 MatrixXd predicted_mean = meanFromSigmaPoints(predicted_sigma_points, graft_state_.rows(), lambda);
00347 MatrixXd predicted_covariance = covarianceFromSigmaPoints(predicted_sigma_points, predicted_mean, Q_, graft_state_.rows(), alpha_, beta_, lambda);
00348
00349
00350 std::vector<MatrixXd> observation_sigma_points = generateSigmaPoints(predicted_mean, predicted_covariance, lambda);
00351 std::vector<MatrixXd> predicted_observation_sigma_points;
00352 MatrixXd measurement_noise;
00353 MatrixXd z = getMeasurements(topics_, observation_sigma_points, predicted_observation_sigma_points, measurement_noise);
00354 if(z.size() == 0){
00355 return 0.0;
00356 }
00357 MatrixXd predicted_measurement = meanFromSigmaPoints(predicted_observation_sigma_points, graft_state_.rows(), lambda);
00358 MatrixXd predicted_measurement_uncertainty = covarianceFromSigmaPoints(predicted_observation_sigma_points, predicted_measurement, measurement_noise, graft_state_.rows(), alpha_, beta_, lambda);
00359 MatrixXd cross_covariance = crossCovariance(observation_sigma_points, predicted_mean, predicted_observation_sigma_points, predicted_measurement, alpha_, beta_, lambda);
00360 MatrixXd K = cross_covariance * predicted_measurement_uncertainty.partialPivLu().inverse();
00361 graft_state_ = predicted_mean + K*(z - predicted_measurement);
00362 graft_state_.block(0, 0, 4, 1) = unitQuaternion(graft_state_.block(0, 0, 4, 1));
00363 graft_covariance_ = predicted_covariance - K*predicted_measurement_uncertainty*K.transpose();
00364
00365 clearMessages(topics_);
00366 return dt;
00367 }
00368
00369 void GraftUKFAttitude::setTopics(std::vector<boost::shared_ptr<GraftSensor> >& topics){
00370 topics_ = topics;
00371 }
00372
00373 void GraftUKFAttitude::setInitialCovariance(std::vector<double>& P){
00374 graft_covariance_.setZero();
00375 size_t diagonal_size = std::sqrt(graft_covariance_.size());
00376 if(P.size() == graft_covariance_.size()){
00377 for(size_t i = 0; i < P.size(); i++){
00378 graft_covariance_(i) = P[i];
00379 }
00380 } else if(P.size() == diagonal_size){
00381 for(size_t i = 0; i < P.size(); i++){
00382 graft_covariance_(i*(diagonal_size+1)) = P[i];
00383 }
00384 } else {
00385 ROS_ERROR("initial_covariance is size %zu, expected %zu.\nUsing Identity.\nThis probably won't work well.", P.size(), graft_covariance_.size());
00386 graft_covariance_.setIdentity();
00387 }
00388 std::cout << "cov:\n" << graft_covariance_ << std::endl;
00389 }
00390
00391 void GraftUKFAttitude::setProcessNoise(std::vector<double>& Q){
00392 Q_.setZero();
00393 size_t diagonal_size = std::sqrt(Q_.size());
00394 if(Q.size() == Q_.size()){
00395 for(size_t i = 0; i < Q.size(); i++){
00396 Q_(i) = Q[i];
00397 }
00398 } else if(Q.size() == diagonal_size){
00399 for(size_t i = 0; i < Q.size(); i++){
00400 Q_(i*(diagonal_size+1)) = Q[i];
00401 }
00402 } else {
00403 ROS_ERROR("Process noise parameter 'Q' is size %zu, expected %zu.\nUsing 0.1*Identity.\nThis probably won't work well.", Q.size(), Q_.size());
00404 Q_.setIdentity();
00405 Q_ = 0.1 * Q_;
00406 }
00407 }
00408
00409 void GraftUKFAttitude::setAlpha(const double alpha){
00410 alpha_ = alpha;
00411 }
00412
00413 void GraftUKFAttitude::setKappa(const double kappa){
00414 kappa_ = kappa;
00415 }
00416
00417 void GraftUKFAttitude::setBeta(const double beta){
00418 beta_ = beta;
00419 }