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 #include "robot_localization/ros_filter.h"
00034 #include "robot_localization/filter_utilities.h"
00035 #include "robot_localization/ekf.h"
00036 #include "robot_localization/ukf.h"
00037
00038 namespace RobotLocalization
00039 {
00040 template<typename T>
00041 RosFilter<T>::RosFilter(std::vector<double> args) :
00042 staticDiagErrorLevel_(diagnostic_msgs::DiagnosticStatus::OK),
00043 dynamicDiagErrorLevel_(diagnostic_msgs::DiagnosticStatus::OK),
00044 filter_(args),
00045 frequency_(30.0),
00046 lastSetPoseTime_(0),
00047 nhLocal_("~"),
00048 printDiagnostics_(true),
00049 twoDMode_(false)
00050 {
00051 stateVariableNames_.push_back("X");
00052 stateVariableNames_.push_back("Y");
00053 stateVariableNames_.push_back("Z");
00054 stateVariableNames_.push_back("ROLL");
00055 stateVariableNames_.push_back("PITCH");
00056 stateVariableNames_.push_back("YAW");
00057 stateVariableNames_.push_back("X_VELOCITY");
00058 stateVariableNames_.push_back("Y_VELOCITY");
00059 stateVariableNames_.push_back("Z_VELOCITY");
00060 stateVariableNames_.push_back("ROLL_VELOCITY");
00061 stateVariableNames_.push_back("PITCH_VELOCITY");
00062 stateVariableNames_.push_back("YAW_VELOCITY");
00063 stateVariableNames_.push_back("X_ACCELERATION");
00064 stateVariableNames_.push_back("Y_ACCELERATION");
00065 stateVariableNames_.push_back("Z_ACCELERATION");
00066
00067 diagnosticUpdater_.setHardwareID("none");
00068 }
00069
00070 template<typename T>
00071 RosFilter<T>::~RosFilter()
00072 {
00073 poseMessageFilters_.clear();
00074 twistMessageFilters_.clear();
00075 accelerationMessageFilters_.clear();
00076 poseTopicSubs_.clear();
00077 twistTopicSubs_.clear();
00078 imuTopicSubs_.clear();
00079 odomTopicSubs_.clear();
00080 }
00081
00082 template<typename T>
00083 void RosFilter<T>::accelerationCallback(const sensor_msgs::Imu::ConstPtr &msg,
00084 const std::string &topicName,
00085 const std::string &targetFrame,
00086 const std::vector<int> &updateVector,
00087 const double mahalanobisThresh)
00088 {
00089
00090
00091 if(msg->header.stamp <= lastSetPoseTime_)
00092 {
00093 return;
00094 }
00095
00096 RF_DEBUG("------ RosFilter::accelerationCallback (" << topicName << ") ------\n"
00097 "Twist message:\n" << *msg);
00098
00099 if (lastMessageTimes_.count(topicName) == 0)
00100 {
00101 lastMessageTimes_.insert(std::pair<std::string, ros::Time>(topicName, msg->header.stamp));
00102 }
00103
00104
00105 if (msg->header.stamp >= lastMessageTimes_[topicName])
00106 {
00107 RF_DEBUG("Update vector for " << topicName << " is:\n" << updateVector);
00108
00109 Eigen::VectorXd measurement(STATE_SIZE);
00110 Eigen::MatrixXd measurementCovariance(STATE_SIZE, STATE_SIZE);
00111
00112 measurement.setZero();
00113 measurementCovariance.setZero();
00114
00115
00116 if (updateVector[StateMemberAx] || updateVector[StateMemberAy] || updateVector[StateMemberAz])
00117 {
00118 std::vector<int> updateVectorCorrected = updateVector;
00119
00120
00121 if (prepareAcceleration(msg, topicName, targetFrame, updateVectorCorrected, measurement, measurementCovariance))
00122 {
00123
00124
00125 enqueueMeasurement(topicName, measurement, measurementCovariance, updateVectorCorrected, mahalanobisThresh, msg->header.stamp);
00126
00127 RF_DEBUG("Enqueued new measurement for " << topicName << "_acceleration\n");
00128 }
00129 else
00130 {
00131 RF_DEBUG("Did *not* enqueue measurement for " << topicName << "_acceleration\n");
00132 }
00133 }
00134 else
00135 {
00136 RF_DEBUG("Update vector for " << topicName << " is such that none of its state variables will be updated\n");
00137 }
00138
00139 lastMessageTimes_[topicName] = msg->header.stamp;
00140
00141 RF_DEBUG("Last message time for " << topicName << " is now " << lastMessageTimes_[topicName] << "\n");
00142 }
00143 else
00144 {
00145 RF_DEBUG("Message is too old. Last message time for " << topicName <<
00146 " is " << lastMessageTimes_[topicName] << ", current message time is " <<
00147 msg->header.stamp << ".\n");
00148 }
00149
00150 RF_DEBUG("\n----- /RosFilter::accelerationCallback (" << topicName << ") ------\n");
00151 }
00152
00153 template<typename T>
00154 void RosFilter<T>::enqueueMeasurement(const std::string &topicName,
00155 const Eigen::VectorXd &measurement,
00156 const Eigen::MatrixXd &measurementCovariance,
00157 const std::vector<int> &updateVector,
00158 const double mahalanobisThresh,
00159 const ros::Time &time)
00160 {
00161 Measurement meas;
00162
00163 meas.topicName_ = topicName;
00164 meas.measurement_ = measurement;
00165 meas.covariance_ = measurementCovariance;
00166 meas.updateVector_ = updateVector;
00167 meas.time_ = time.toSec();
00168 meas.mahalanobisThresh_ = mahalanobisThresh;
00169 measurementQueue_.push(meas);
00170 }
00171
00172 template<typename T>
00173 void RosFilter<T>::forceTwoD(Eigen::VectorXd &measurement,
00174 Eigen::MatrixXd &measurementCovariance,
00175 std::vector<int> &updateVector)
00176 {
00177 measurement(StateMemberZ) = 0.0;
00178 measurement(StateMemberRoll) = 0.0;
00179 measurement(StateMemberPitch) = 0.0;
00180 measurement(StateMemberVz) = 0.0;
00181 measurement(StateMemberVroll) = 0.0;
00182 measurement(StateMemberVpitch) = 0.0;
00183 measurement(StateMemberAz) = 0.0;
00184
00185 measurementCovariance(StateMemberZ, StateMemberZ) = 1e-6;
00186 measurementCovariance(StateMemberRoll, StateMemberRoll) = 1e-6;
00187 measurementCovariance(StateMemberPitch, StateMemberPitch) = 1e-6;
00188 measurementCovariance(StateMemberVz, StateMemberVz) = 1e-6;
00189 measurementCovariance(StateMemberVroll, StateMemberVroll) = 1e-6;
00190 measurementCovariance(StateMemberVpitch, StateMemberVpitch) = 1e-6;
00191 measurementCovariance(StateMemberAz, StateMemberAz) = 1e-6;
00192
00193 updateVector[StateMemberZ] = 1;
00194 updateVector[StateMemberRoll] = 1;
00195 updateVector[StateMemberPitch] = 1;
00196 updateVector[StateMemberVz] = 1;
00197 updateVector[StateMemberVroll] = 1;
00198 updateVector[StateMemberVpitch] = 1;
00199 updateVector[StateMemberAz] = 1;
00200 }
00201
00202 template<typename T>
00203 bool RosFilter<T>::getFilteredOdometryMessage(nav_msgs::Odometry &message)
00204 {
00205
00206 if (filter_.getInitializedStatus())
00207 {
00208
00209 const Eigen::VectorXd &state = filter_.getState();
00210 const Eigen::MatrixXd &estimateErrorCovariance = filter_.getEstimateErrorCovariance();
00211
00212
00213
00214 tf::Quaternion quat;
00215 quat.setRPY(state(StateMemberRoll), state(StateMemberPitch), state(StateMemberYaw));
00216
00217
00218 message.pose.pose.position.x = state(StateMemberX);
00219 message.pose.pose.position.y = state(StateMemberY);
00220 message.pose.pose.position.z = state(StateMemberZ);
00221 message.pose.pose.orientation.x = quat.x();
00222 message.pose.pose.orientation.y = quat.y();
00223 message.pose.pose.orientation.z = quat.z();
00224 message.pose.pose.orientation.w = quat.w();
00225 message.twist.twist.linear.x = state(StateMemberVx);
00226 message.twist.twist.linear.y = state(StateMemberVy);
00227 message.twist.twist.linear.z = state(StateMemberVz);
00228 message.twist.twist.angular.x = state(StateMemberVroll);
00229 message.twist.twist.angular.y = state(StateMemberVpitch);
00230 message.twist.twist.angular.z = state(StateMemberVyaw);
00231
00232
00233 for (size_t i = 0; i < POSE_SIZE; i++)
00234 {
00235 for (size_t j = 0; j < POSE_SIZE; j++)
00236 {
00237 message.pose.covariance[POSE_SIZE * i + j] = estimateErrorCovariance(i, j);
00238 }
00239 }
00240
00241
00242
00243
00244 for (size_t i = 0; i < TWIST_SIZE; i++)
00245 {
00246 for (size_t j = 0; j < TWIST_SIZE; j++)
00247 {
00248 message.twist.covariance[TWIST_SIZE * i + j] = estimateErrorCovariance(i + POSITION_V_OFFSET, j + POSITION_V_OFFSET);
00249 }
00250 }
00251
00252 message.header.stamp = ros::Time::now();
00253 message.header.frame_id = worldFrameId_;
00254 message.child_frame_id = baseLinkFrameId_;
00255 }
00256
00257 return filter_.getInitializedStatus();
00258 }
00259
00260 template<typename T>
00261 void RosFilter<T>::imuCallback(const sensor_msgs::Imu::ConstPtr &msg,
00262 const std::string &topicName)
00263 {
00264
00265
00266 if(msg->header.stamp <= lastSetPoseTime_)
00267 {
00268 return;
00269 }
00270
00271 RF_DEBUG("------ RosFilter::imuCallback (" << topicName << ") ------\n" <<
00272 "IMU message:\n" << *msg);
00273
00274
00275
00276
00277 std::string imuPoseTopicName = topicName + "_pose";
00278 if(poseMessageFilters_.count(imuPoseTopicName) > 0)
00279 {
00280
00281 geometry_msgs::PoseWithCovarianceStamped *posPtr = new geometry_msgs::PoseWithCovarianceStamped();
00282 posPtr->header = msg->header;
00283 posPtr->pose.pose.orientation = msg->orientation;
00284
00285
00286 for (size_t i = 0; i < ORIENTATION_SIZE; i++)
00287 {
00288 for (size_t j = 0; j < ORIENTATION_SIZE; j++)
00289 {
00290 posPtr->pose.covariance[POSE_SIZE * (i + ORIENTATION_SIZE) + (j + ORIENTATION_SIZE)] = msg->orientation_covariance[ORIENTATION_SIZE * i + j];
00291 }
00292 }
00293
00294 geometry_msgs::PoseWithCovarianceStampedConstPtr pptr(posPtr);
00295 poseMessageFilters_[imuPoseTopicName]->add(pptr);
00296 }
00297
00298 std::string imuTwistTopicName = topicName + "_twist";
00299 if(twistMessageFilters_.count(imuTwistTopicName) > 0)
00300 {
00301
00302 geometry_msgs::TwistWithCovarianceStamped *twistPtr = new geometry_msgs::TwistWithCovarianceStamped();
00303 twistPtr->header = msg->header;
00304 twistPtr->twist.twist.angular = msg->angular_velocity;
00305
00306
00307 for (size_t i = 0; i < ORIENTATION_SIZE; i++)
00308 {
00309 for (size_t j = 0; j < ORIENTATION_SIZE; j++)
00310 {
00311 twistPtr->twist.covariance[TWIST_SIZE * (i + ORIENTATION_SIZE) + (j + ORIENTATION_SIZE)] = msg->angular_velocity_covariance[ORIENTATION_SIZE * i + j];
00312 }
00313 }
00314
00315 geometry_msgs::TwistWithCovarianceStampedConstPtr tptr(twistPtr);
00316 twistMessageFilters_[imuTwistTopicName]->add(tptr);
00317 }
00318
00319 std::string imuAccelTopicName = topicName + "_acceleration";
00320 if(accelerationMessageFilters_.count(imuAccelTopicName) > 0)
00321 {
00322
00323
00324
00325 accelerationMessageFilters_[imuAccelTopicName]->add(msg);
00326 }
00327
00328 RF_DEBUG("\n----- /RosFilter::imuCallback (" << topicName << ") ------\n");
00329 }
00330
00331 template<typename T>
00332 void RosFilter<T>::integrateMeasurements(const double currentTime)
00333 {
00334 RF_DEBUG("------ RosFilter::integrateMeasurements ------\n\n"
00335 "Integration time is " << std::setprecision(20) << currentTime << "\n"
00336 << measurementQueue_.size() << " measurements in queue.\n");
00337
00338
00339 if (!measurementQueue_.empty())
00340 {
00341 while (!measurementQueue_.empty())
00342 {
00343 Measurement measurement = measurementQueue_.top();
00344 measurementQueue_.pop();
00345
00346
00347 filter_.processMeasurement(measurement);
00348 }
00349
00350 filter_.setLastUpdateTime(currentTime);
00351 }
00352 else if (filter_.getInitializedStatus())
00353 {
00354
00355
00356
00357 double lastUpdateDelta = currentTime - filter_.getLastUpdateTime();
00358
00359
00360 if(lastUpdateDelta >= filter_.getSensorTimeout())
00361 {
00362 RF_DEBUG("Sensor timeout! Last update time was " << filter_.getLastUpdateTime() <<
00363 ", current time is " << currentTime <<
00364 ", delta is " << lastUpdateDelta << "\n");
00365
00366 filter_.validateDelta(lastUpdateDelta);
00367 filter_.predict(lastUpdateDelta);
00368
00369
00370 filter_.setLastMeasurementTime(filter_.getLastMeasurementTime() + lastUpdateDelta);
00371 filter_.setLastUpdateTime(filter_.getLastUpdateTime() + lastUpdateDelta);
00372 }
00373 }
00374 else
00375 {
00376 RF_DEBUG("Filter not yet initialized.\n");
00377 }
00378
00379 RF_DEBUG("\n----- /RosFilter::integrateMeasurements ------\n");
00380 }
00381
00382 template<typename T>
00383 void RosFilter<T>::loadParams()
00384 {
00385
00386
00387
00388
00389 std::map<StateMembers, int> absPoseVarCounts;
00390 absPoseVarCounts[StateMemberX] = 0;
00391 absPoseVarCounts[StateMemberY] = 0;
00392 absPoseVarCounts[StateMemberZ] = 0;
00393 absPoseVarCounts[StateMemberRoll] = 0;
00394 absPoseVarCounts[StateMemberPitch] = 0;
00395 absPoseVarCounts[StateMemberYaw] = 0;
00396
00397
00398 std::map<StateMembers, int> twistVarCounts;
00399 twistVarCounts[StateMemberVx] = 0;
00400 twistVarCounts[StateMemberVy] = 0;
00401 twistVarCounts[StateMemberVz] = 0;
00402 twistVarCounts[StateMemberVroll] = 0;
00403 twistVarCounts[StateMemberVpitch] = 0;
00404 twistVarCounts[StateMemberVyaw] = 0;
00405
00406
00407 nhLocal_.param("print_diagnostics", printDiagnostics_, true);
00408
00409
00410 bool debug;
00411 nhLocal_.param("debug", debug, false);
00412
00413 if (debug)
00414 {
00415 std::string debugOutFile;
00416
00417 try
00418 {
00419 nhLocal_.param("debug_out_file", debugOutFile, std::string("robot_localization_debug.txt"));
00420 debugStream_.open(debugOutFile.c_str());
00421
00422
00423 if(debugStream_.is_open())
00424 {
00425 filter_.setDebug(debug, &debugStream_);
00426 }
00427 else
00428 {
00429 ROS_WARN_STREAM("RosFilter::loadParams() - unable to create debug output file " << debugOutFile);
00430 }
00431 }
00432 catch(const std::exception &e)
00433 {
00434 ROS_WARN_STREAM("RosFilter::loadParams() - unable to create debug output file" << debugOutFile
00435 << ". Error was " << e.what() << "\n");
00436 }
00437 }
00438
00439
00440 nh_.param("/tf_prefix", tfPrefix_, std::string(""));
00441
00442 if (tfPrefix_.empty())
00443 {
00444 nh_.param("tf_prefix", tfPrefix_, std::string(""));
00445 }
00446
00447
00448
00449 nhLocal_.param("map_frame", mapFrameId_, std::string("map"));
00450 nhLocal_.param("odom_frame", odomFrameId_, std::string("odom"));
00451 nhLocal_.param("base_link_frame", baseLinkFrameId_, std::string("base_link"));
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 nhLocal_.param("world_frame", worldFrameId_, odomFrameId_);
00479
00480 ROS_FATAL_COND(mapFrameId_ == odomFrameId_ ||
00481 odomFrameId_ == baseLinkFrameId_ ||
00482 mapFrameId_ == baseLinkFrameId_,
00483 "Invalid frame configuration! The values for map_frame, odom_frame, and base_link_frame must be unique");
00484
00485
00486 if (!tfPrefix_.empty() && baseLinkFrameId_.at(0) != '/')
00487 {
00488 if(mapFrameId_.at(0) != '/')
00489 {
00490 mapFrameId_ = "/" + tfPrefix_ + "/" + mapFrameId_;
00491 }
00492
00493 if(odomFrameId_.at(0) != '/')
00494 {
00495 odomFrameId_ = "/" + tfPrefix_ + "/" + odomFrameId_;
00496 }
00497
00498 if(baseLinkFrameId_.at(0) != '/')
00499 {
00500 baseLinkFrameId_ = "/" + tfPrefix_ + "/" + baseLinkFrameId_;
00501 }
00502 }
00503
00504
00505 double offsetTmp;
00506 nhLocal_.param("transform_time_offset", offsetTmp, 0.0);
00507 tfTimeOffset_.fromSec(offsetTmp);
00508
00509
00510 double sensorTimeout;
00511 nhLocal_.param("frequency", frequency_, 30.0);
00512 nhLocal_.param("sensor_timeout", sensorTimeout, 1.0 / frequency_);
00513 filter_.setSensorTimeout(sensorTimeout);
00514
00515
00516 nhLocal_.param("two_d_mode", twoDMode_, false);
00517
00518
00519 RF_DEBUG("tf_prefix is " << tfPrefix_ <<
00520 "\nmap_frame is " << mapFrameId_ <<
00521 "\nodom_frame is " << odomFrameId_ <<
00522 "\nbase_link_frame is " << baseLinkFrameId_ <<
00523 "\nworld_frame is " << worldFrameId_ <<
00524 "\ntransform_time_offset is " << tfTimeOffset_.toSec() <<
00525 "\nfrequency is " << frequency_ <<
00526 "\nsensor_timeout is " << filter_.getSensorTimeout() <<
00527 "\ntwo_d_mode is " << (twoDMode_ ? "true" : "false") <<
00528 "\nprint_diagnostics is " << (printDiagnostics_ ? "true" : "false") << "\n");
00529
00530
00531 setPoseSub_ = nh_.subscribe<geometry_msgs::PoseWithCovarianceStamped>("set_pose", 1, &RosFilter<T>::setPoseCallback, this);
00532
00533
00534 setPoseSrv_ = nh_.advertiseService("set_pose", &RosFilter<T>::setPoseSrvCallback, this);
00535
00536
00537 filter_.setLastMeasurementTime(ros::Time::now().toSec());
00538 filter_.setLastUpdateTime(ros::Time::now().toSec());
00539
00540
00541
00542 size_t topicInd = 0;
00543 bool moreParams = false;
00544 do
00545 {
00546
00547
00548
00549 std::stringstream ss;
00550 ss << "odom" << topicInd++;
00551 std::string odomTopicName = ss.str();
00552 moreParams = nhLocal_.hasParam(odomTopicName);
00553
00554 if (moreParams)
00555 {
00556
00557 bool differential;
00558 nhLocal_.param(odomTopicName + std::string("_differential"), differential, false);
00559
00560
00561 bool relative;
00562 nhLocal_.param(odomTopicName + std::string("_relative"), relative, false);
00563
00564 if(relative && differential)
00565 {
00566 ROS_WARN_STREAM("Both " << odomTopicName << "_differential" << " and " << odomTopicName <<
00567 "_relative were set to true. Using differential mode.");
00568
00569 relative = false;
00570 }
00571
00572 std::string odomTopic;
00573 nhLocal_.getParam(odomTopicName, odomTopic);
00574
00575
00576 double poseMahalanobisThresh;
00577 nhLocal_.param(odomTopicName + std::string("_pose_rejection_threshold"), poseMahalanobisThresh, std::numeric_limits<double>::max());
00578
00579
00580 double twistMahalanobisThresh;
00581 nhLocal_.param(odomTopicName + std::string("_twist_rejection_threshold"), twistMahalanobisThresh, std::numeric_limits<double>::max());
00582
00583
00584
00585
00586 std::vector<int> updateVec = loadUpdateConfig(odomTopicName);
00587 std::vector<int> poseUpdateVec = updateVec;
00588 std::fill(poseUpdateVec.begin() + POSITION_V_OFFSET, poseUpdateVec.begin() + POSITION_V_OFFSET + TWIST_SIZE, 0);
00589 std::vector<int> twistUpdateVec = updateVec;
00590 std::fill(twistUpdateVec.begin() + POSITION_OFFSET, twistUpdateVec.begin() + POSITION_OFFSET + POSE_SIZE, 0);
00591
00592 int poseUpdateSum = std::accumulate(poseUpdateVec.begin(), poseUpdateVec.end(), 0);
00593 int twistUpdateSum = std::accumulate(twistUpdateVec.begin(), twistUpdateVec.end(), 0);
00594
00595
00596
00597
00598
00599
00600
00601
00602 int odomQueueSize = 1;
00603 nhLocal_.param(odomTopicName + "_queue_size", odomQueueSize, 1);
00604
00605 if(poseUpdateSum + twistUpdateSum > 0)
00606 {
00607 odomTopicSubs_.push_back(
00608 nh_.subscribe<nav_msgs::Odometry>(odomTopic, odomQueueSize,
00609 boost::bind(&RosFilter<T>::odometryCallback, this, _1, odomTopicName)));
00610 }
00611 else
00612 {
00613 std::stringstream stream;
00614 stream << odomTopic << " is listed as an input topic, but all update variables are false";
00615
00616 addDiagnostic(diagnostic_msgs::DiagnosticStatus::WARN,
00617 odomTopic + "_configuration",
00618 stream.str(),
00619 true);
00620 }
00621
00622 if(poseUpdateSum > 0)
00623 {
00624 poseMFPtr poseFilPtr(new tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>(tfListener_, worldFrameId_, odomQueueSize));
00625 std::string odomPoseTopicName = odomTopicName + "_pose";
00626 poseFilPtr->registerCallback(boost::bind(&RosFilter<T>::poseCallback, this, _1, odomPoseTopicName, worldFrameId_, poseUpdateVec, differential, relative, false, poseMahalanobisThresh));
00627 poseFilPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformPoseFailureCallback, this, _1, _2, odomTopicName, worldFrameId_));
00628 poseMessageFilters_[odomPoseTopicName] = poseFilPtr;
00629
00630 if(differential)
00631 {
00632 twistVarCounts[StateMemberVx] += poseUpdateVec[StateMemberX];
00633 twistVarCounts[StateMemberVy] += poseUpdateVec[StateMemberY];
00634 twistVarCounts[StateMemberVz] += poseUpdateVec[StateMemberZ];
00635 twistVarCounts[StateMemberVroll] += poseUpdateVec[StateMemberRoll];
00636 twistVarCounts[StateMemberVpitch] += poseUpdateVec[StateMemberPitch];
00637 twistVarCounts[StateMemberVyaw] += poseUpdateVec[StateMemberYaw];
00638 }
00639 else
00640 {
00641 absPoseVarCounts[StateMemberX] += poseUpdateVec[StateMemberX];
00642 absPoseVarCounts[StateMemberY] += poseUpdateVec[StateMemberY];
00643 absPoseVarCounts[StateMemberZ] += poseUpdateVec[StateMemberZ];
00644 absPoseVarCounts[StateMemberRoll] += poseUpdateVec[StateMemberRoll];
00645 absPoseVarCounts[StateMemberPitch] += poseUpdateVec[StateMemberPitch];
00646 absPoseVarCounts[StateMemberYaw] += poseUpdateVec[StateMemberYaw];
00647 }
00648 }
00649
00650 if(twistUpdateSum > 0)
00651 {
00652 twistMFPtr twistFilPtr(new tf::MessageFilter<geometry_msgs::TwistWithCovarianceStamped>(tfListener_, baseLinkFrameId_, odomQueueSize));
00653 std::string odomTwistTopicName = odomTopicName + "_twist";
00654 twistFilPtr->registerCallback(boost::bind(&RosFilter<T>::twistCallback, this, _1, odomTwistTopicName, baseLinkFrameId_, twistUpdateVec, twistMahalanobisThresh));
00655 twistFilPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformTwistFailureCallback, this, _1, _2, odomTopicName, baseLinkFrameId_));
00656 twistMessageFilters_[odomTwistTopicName] = twistFilPtr;
00657
00658 twistVarCounts[StateMemberVx] += twistUpdateVec[StateMemberVx];
00659 twistVarCounts[StateMemberVy] += twistUpdateVec[StateMemberVx];
00660 twistVarCounts[StateMemberVz] += twistUpdateVec[StateMemberVz];
00661 twistVarCounts[StateMemberVroll] += twistUpdateVec[StateMemberVroll];
00662 twistVarCounts[StateMemberVpitch] += twistUpdateVec[StateMemberVpitch];
00663 twistVarCounts[StateMemberVyaw] += twistUpdateVec[StateMemberVyaw];
00664 }
00665
00666 RF_DEBUG("Subscribed to " << odomTopic << " (" << odomTopicName << ")\n\t" <<
00667 odomTopicName << "_differential is " << (differential ? "true" : "false") << "\n\t" <<
00668 odomTopicName << "_pose_rejection_threshold is " << poseMahalanobisThresh << "\n\t" <<
00669 odomTopicName << "_twist_rejection_threshold is " << twistMahalanobisThresh << "\n\t" <<
00670 odomTopicName << "_queue_size is " << odomQueueSize << "\n\t" <<
00671 odomTopicName << " pose update vector is " << poseUpdateVec << "\t"<<
00672 odomTopicName << " twist update vector is " << twistUpdateVec);
00673 }
00674 } while (moreParams);
00675
00676
00677 topicInd = 0;
00678 moreParams = false;
00679 do
00680 {
00681 std::stringstream ss;
00682 ss << "pose" << topicInd++;
00683 std::string poseTopicName = ss.str();
00684 moreParams = nhLocal_.hasParam(poseTopicName);
00685
00686 if (moreParams)
00687 {
00688 bool differential;
00689 nhLocal_.param(poseTopicName + std::string("_differential"), differential, false);
00690
00691
00692 bool relative;
00693 nhLocal_.param(poseTopicName + std::string("_relative"), relative, false);
00694
00695 if(relative && differential)
00696 {
00697 ROS_WARN_STREAM("Both " << poseTopicName << "_differential" << " and " << poseTopicName <<
00698 "_relative were set to true. Using differential mode.");
00699
00700 relative = false;
00701 }
00702
00703 std::string poseTopic;
00704 nhLocal_.getParam(poseTopicName, poseTopic);
00705
00706
00707 double poseMahalanobisThresh;
00708 nhLocal_.param(poseTopicName + std::string("_rejection_threshold"), poseMahalanobisThresh, std::numeric_limits<double>::max());
00709
00710 int poseQueueSize = 1;
00711 nhLocal_.param(poseTopicName + "_queue_size", poseQueueSize, 1);
00712
00713
00714 std::vector<int> poseUpdateVec = loadUpdateConfig(poseTopicName);
00715 std::fill(poseUpdateVec.begin() + POSITION_V_OFFSET, poseUpdateVec.begin() + POSITION_V_OFFSET + TWIST_SIZE, 0);
00716 std::fill(poseUpdateVec.begin() + POSITION_A_OFFSET, poseUpdateVec.begin() + POSITION_A_OFFSET + ACCELERATION_SIZE, 0);
00717
00718 int poseUpdateSum = std::accumulate(poseUpdateVec.begin(), poseUpdateVec.end(), 0);
00719
00720 if(poseUpdateSum > 0)
00721 {
00722
00723 poseMFSubPtr subPtr(new message_filters::Subscriber<geometry_msgs::PoseWithCovarianceStamped>());
00724 subPtr->subscribe(nh_, poseTopic, poseQueueSize);
00725 poseMFPtr filPtr(new tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>(*subPtr, tfListener_, worldFrameId_, poseQueueSize));
00726 filPtr->registerCallback(boost::bind(&RosFilter<T>::poseCallback, this, _1, poseTopicName, worldFrameId_, poseUpdateVec, differential, relative, false, poseMahalanobisThresh));
00727 filPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformPoseFailureCallback, this, _1, _2, poseTopicName, worldFrameId_));
00728 poseTopicSubs_.push_back(subPtr);
00729 poseMessageFilters_[poseTopicName] = filPtr;
00730
00731 if(differential)
00732 {
00733 twistVarCounts[StateMemberVx] += poseUpdateVec[StateMemberX];
00734 twistVarCounts[StateMemberVy] += poseUpdateVec[StateMemberY];
00735 twistVarCounts[StateMemberVz] += poseUpdateVec[StateMemberZ];
00736 twistVarCounts[StateMemberVroll] += poseUpdateVec[StateMemberRoll];
00737 twistVarCounts[StateMemberVpitch] += poseUpdateVec[StateMemberPitch];
00738 twistVarCounts[StateMemberVyaw] += poseUpdateVec[StateMemberYaw];
00739 }
00740 else
00741 {
00742 absPoseVarCounts[StateMemberX] += poseUpdateVec[StateMemberX];
00743 absPoseVarCounts[StateMemberY] += poseUpdateVec[StateMemberY];
00744 absPoseVarCounts[StateMemberZ] += poseUpdateVec[StateMemberZ];
00745 absPoseVarCounts[StateMemberRoll] += poseUpdateVec[StateMemberRoll];
00746 absPoseVarCounts[StateMemberPitch] += poseUpdateVec[StateMemberPitch];
00747 absPoseVarCounts[StateMemberYaw] += poseUpdateVec[StateMemberYaw];
00748 }
00749 }
00750 else
00751 {
00752 ROS_WARN_STREAM("Warning: " << poseTopic << " is listed as an input topic, but all pose update variables are false");
00753 }
00754
00755 RF_DEBUG("Subscribed to " << poseTopic << " (" << poseTopicName << ")\n\t" <<
00756 poseTopicName << "_differential is " << (differential ? "true" : "false") << "\n\t" <<
00757 poseTopicName << "_rejection_threshold is " << poseMahalanobisThresh << "\n\t" <<
00758 poseTopicName << "_queue_size is " << poseQueueSize << "\n\t" <<
00759 poseTopicName << " update vector is " << poseUpdateVec);
00760 }
00761 } while (moreParams);
00762
00763
00764 topicInd = 0;
00765 moreParams = false;
00766 do
00767 {
00768 std::stringstream ss;
00769 ss << "twist" << topicInd++;
00770 std::string twistTopicName = ss.str();
00771 moreParams = nhLocal_.hasParam(twistTopicName);
00772
00773 if (moreParams)
00774 {
00775 std::string twistTopic;
00776 nhLocal_.getParam(twistTopicName, twistTopic);
00777
00778
00779 double twistMahalanobisThresh;
00780 nhLocal_.param(twistTopicName + std::string("_rejection_threshold"), twistMahalanobisThresh, std::numeric_limits<double>::max());
00781
00782 int twistQueueSize = 1;
00783 nhLocal_.param(twistTopicName + "_queue_size", twistQueueSize, 1);
00784
00785
00786 std::vector<int> twistUpdateVec = loadUpdateConfig(twistTopicName);
00787 std::fill(twistUpdateVec.begin() + POSITION_OFFSET, twistUpdateVec.begin() + POSITION_OFFSET + POSE_SIZE, 0);
00788
00789 int twistUpdateSum = std::accumulate(twistUpdateVec.begin(), twistUpdateVec.end(), 0);
00790
00791 if(twistUpdateSum > 0)
00792 {
00793
00794 twistMFSubPtr subPtr(new message_filters::Subscriber<geometry_msgs::TwistWithCovarianceStamped>());
00795 subPtr->subscribe(nh_, twistTopic, twistQueueSize);
00796 twistMFPtr filPtr(new tf::MessageFilter<geometry_msgs::TwistWithCovarianceStamped>(*subPtr, tfListener_, baseLinkFrameId_, twistQueueSize));
00797 filPtr->registerCallback(boost::bind(&RosFilter<T>::twistCallback, this, _1, twistTopicName, baseLinkFrameId_, twistUpdateVec, twistMahalanobisThresh));
00798 filPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformTwistFailureCallback, this, _1, _2, twistTopicName, baseLinkFrameId_));
00799 twistTopicSubs_.push_back(subPtr);
00800 twistMessageFilters_[twistTopicName] = filPtr;
00801
00802 twistVarCounts[StateMemberVx] += twistUpdateVec[StateMemberVx];
00803 twistVarCounts[StateMemberVy] += twistUpdateVec[StateMemberVy];
00804 twistVarCounts[StateMemberVz] += twistUpdateVec[StateMemberVz];
00805 twistVarCounts[StateMemberVroll] += twistUpdateVec[StateMemberVroll];
00806 twistVarCounts[StateMemberVpitch] += twistUpdateVec[StateMemberVpitch];
00807 twistVarCounts[StateMemberVyaw] += twistUpdateVec[StateMemberVyaw];
00808 }
00809 else
00810 {
00811 ROS_WARN_STREAM("Warning: " << twistTopic << " is listed as an input topic, but all twist update variables are false");
00812 }
00813
00814 RF_DEBUG("Subscribed to " << twistTopic << " (" << twistTopicName << ")\n\t" <<
00815 twistTopicName << "_rejection_threshold is " << twistMahalanobisThresh << "\n\t" <<
00816 twistTopicName << "_queue_size is " << twistQueueSize << "\n\t" <<
00817 twistTopicName << " update vector is " << twistUpdateVec);
00818 }
00819 } while (moreParams);
00820
00821
00822 topicInd = 0;
00823 moreParams = false;
00824 do
00825 {
00826 std::stringstream ss;
00827 ss << "imu" << topicInd++;
00828 std::string imuTopicName = ss.str();
00829 moreParams = nhLocal_.hasParam(imuTopicName);
00830
00831 if (moreParams)
00832 {
00833 bool differential;
00834 nhLocal_.param(imuTopicName + std::string("_differential"), differential, false);
00835
00836
00837 bool relative;
00838 nhLocal_.param(imuTopicName + std::string("_relative"), relative, false);
00839
00840 if(relative && differential)
00841 {
00842 ROS_WARN_STREAM("Both " << imuTopicName << "_differential" << " and " << imuTopicName <<
00843 "_relative were set to true. Using differential mode.");
00844
00845 relative = false;
00846 }
00847
00848 std::string imuTopic;
00849 nhLocal_.getParam(imuTopicName, imuTopic);
00850
00851
00852 double poseMahalanobisThresh;
00853 nhLocal_.param(imuTopicName + std::string("_pose_rejection_threshold"), poseMahalanobisThresh, std::numeric_limits<double>::max());
00854
00855
00856 double twistMahalanobisThresh;
00857 std::string correctImuTwistRejectionName = imuTopicName + std::string("_twist_rejection_threshold");
00858 std::string deprecatedImuTwistRejectionName = imuTopicName + std::string("_angular_velocity_rejection_threshold");
00859 if(nhLocal_.hasParam(correctImuTwistRejectionName))
00860 {
00861 nhLocal_.param(correctImuTwistRejectionName, twistMahalanobisThresh, std::numeric_limits<double>::max());
00862 }
00863 else if(nhLocal_.hasParam(deprecatedImuTwistRejectionName))
00864 {
00865 nhLocal_.param(deprecatedImuTwistRejectionName, twistMahalanobisThresh, std::numeric_limits<double>::max());
00866
00867 ROS_WARN_STREAM("Detected deprecated parameter " << deprecatedImuTwistRejectionName << ". Please use " <<
00868 correctImuTwistRejectionName << " intstead.");
00869 }
00870 else
00871 {
00872 twistMahalanobisThresh = std::numeric_limits<double>::max();
00873 }
00874
00875
00876 double accelMahalanobisThresh;
00877 nhLocal_.param(imuTopicName + std::string("_linear_acceleration_rejection_threshold"), accelMahalanobisThresh, std::numeric_limits<double>::max());
00878
00879 bool removeGravAcc = false;
00880 if(!nhLocal_.getParam(imuTopicName + "_remove_gravitational_acceleration", removeGravAcc))
00881 {
00882
00883 nhLocal_.param("remove_gravitational_acceleration", removeGravAcc, false);
00884
00885 ROS_WARN_STREAM("Detected deprecated parameter remove_gravitational_acceleration. Please specify this " <<
00886 "parameter for each IMU, e.g., " << imuTopicName + "_remove_gravitational_acceleration");
00887 }
00888 removeGravitationalAcc_[imuTopicName + "_acceleration"] = removeGravAcc;
00889
00890
00891
00892 std::vector<int> updateVec = loadUpdateConfig(imuTopicName);
00893
00894 std::vector<int> poseUpdateVec = updateVec;
00895 std::fill(poseUpdateVec.begin() + POSITION_V_OFFSET, poseUpdateVec.begin() + POSITION_V_OFFSET + TWIST_SIZE, 0);
00896 std::fill(poseUpdateVec.begin() + POSITION_A_OFFSET, poseUpdateVec.begin() + POSITION_A_OFFSET + ACCELERATION_SIZE, 0);
00897
00898 std::vector<int> twistUpdateVec = updateVec;
00899 std::fill(twistUpdateVec.begin() + POSITION_OFFSET, twistUpdateVec.begin() + POSITION_OFFSET + POSE_SIZE, 0);
00900 std::fill(twistUpdateVec.begin() + POSITION_A_OFFSET, twistUpdateVec.begin() + POSITION_A_OFFSET + ACCELERATION_SIZE, 0);
00901
00902 std::vector<int> accelUpdateVec = updateVec;
00903 std::fill(accelUpdateVec.begin() + POSITION_OFFSET, accelUpdateVec.begin() + POSITION_OFFSET + POSE_SIZE, 0);
00904 std::fill(accelUpdateVec.begin() + POSITION_V_OFFSET, accelUpdateVec.begin() + POSITION_V_OFFSET + TWIST_SIZE, 0);
00905
00906 int poseUpdateSum = std::accumulate(poseUpdateVec.begin(), poseUpdateVec.end(), 0);
00907 int twistUpdateSum = std::accumulate(twistUpdateVec.begin(), twistUpdateVec.end(), 0);
00908 int accelUpdateSum = std::accumulate(accelUpdateVec.begin(), accelUpdateVec.end(), 0);
00909
00910 int imuQueueSize = 1;
00911 nhLocal_.param(imuTopicName + "_queue_size", imuQueueSize, 1);
00912
00913 if(poseUpdateSum + twistUpdateSum + accelUpdateSum > 0)
00914 {
00915
00916 imuTopicSubs_.push_back(
00917 nh_.subscribe<sensor_msgs::Imu>(imuTopic, imuQueueSize,
00918 boost::bind(&RosFilter<T>::imuCallback, this, _1, imuTopicName)));
00919 }
00920 else
00921 {
00922 ROS_WARN_STREAM("Warning: " << imuTopic << " is listed as an input topic, but all its update variables are false");
00923 }
00924
00925 if(poseUpdateSum > 0)
00926 {
00927
00928 poseMFPtr poseFilPtr(new tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>(tfListener_, baseLinkFrameId_, imuQueueSize));
00929 std::string imuPoseTopicName = imuTopicName + "_pose";
00930 poseFilPtr->registerCallback(boost::bind(&RosFilter<T>::poseCallback, this, _1, imuPoseTopicName, baseLinkFrameId_, poseUpdateVec, differential, relative, true, poseMahalanobisThresh));
00931 poseFilPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformPoseFailureCallback, this, _1, _2, imuTopicName, baseLinkFrameId_));
00932 poseMessageFilters_[imuPoseTopicName] = poseFilPtr;
00933
00934 if(differential)
00935 {
00936 twistVarCounts[StateMemberVroll] += poseUpdateVec[StateMemberRoll];
00937 twistVarCounts[StateMemberVpitch] += poseUpdateVec[StateMemberPitch];
00938 twistVarCounts[StateMemberVyaw] += poseUpdateVec[StateMemberYaw];
00939 }
00940 else
00941 {
00942 absPoseVarCounts[StateMemberRoll] += poseUpdateVec[StateMemberRoll];
00943 absPoseVarCounts[StateMemberPitch] += poseUpdateVec[StateMemberPitch];
00944 absPoseVarCounts[StateMemberYaw] += poseUpdateVec[StateMemberYaw];
00945 }
00946 }
00947
00948 if(twistUpdateSum > 0)
00949 {
00950 twistMFPtr twistFilPtr(new tf::MessageFilter<geometry_msgs::TwistWithCovarianceStamped>(tfListener_, baseLinkFrameId_, imuQueueSize));
00951 std::string imuTwistTopicName = imuTopicName + "_twist";
00952 twistFilPtr->registerCallback(boost::bind(&RosFilter<T>::twistCallback, this, _1, imuTwistTopicName, baseLinkFrameId_, twistUpdateVec, twistMahalanobisThresh));
00953 twistFilPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformTwistFailureCallback, this, _1, _2, imuTopicName, baseLinkFrameId_));
00954 twistMessageFilters_[imuTwistTopicName] = twistFilPtr;
00955
00956 twistVarCounts[StateMemberVroll] += twistUpdateVec[StateMemberVroll];
00957 twistVarCounts[StateMemberVpitch] += twistUpdateVec[StateMemberVpitch];
00958 twistVarCounts[StateMemberVyaw] += twistUpdateVec[StateMemberVyaw];
00959 }
00960
00961 if(accelUpdateSum > 0)
00962 {
00963 imuMFPtr accelFilPtr(new tf::MessageFilter<sensor_msgs::Imu>(tfListener_, baseLinkFrameId_, imuQueueSize));
00964 std::string imuAccelTopicName = imuTopicName + "_acceleration";
00965 accelFilPtr->registerCallback(boost::bind(&RosFilter<T>::accelerationCallback, this, _1, imuAccelTopicName, baseLinkFrameId_, accelUpdateVec, accelMahalanobisThresh));
00966 accelFilPtr->registerFailureCallback(boost::bind(&RosFilter<T>::transformImuFailureCallback, this, _1, _2, imuTopicName, baseLinkFrameId_));
00967 accelerationMessageFilters_[imuAccelTopicName] = accelFilPtr;
00968 }
00969
00970 RF_DEBUG("Subscribed to " << imuTopic << " (" << imuTopicName << ")\n\t" <<
00971 imuTopicName << "_differential is " << (differential ? "true" : "false") << "\n\t" <<
00972 imuTopicName << "_pose_rejection_threshold is " << poseMahalanobisThresh << "\n\t" <<
00973 imuTopicName << "_twist_rejection_threshold is " << twistMahalanobisThresh << "\n\t" <<
00974 imuTopicName << "_linear_acceleration_rejection_threshold is " << accelMahalanobisThresh << "\n\t" <<
00975 imuTopicName << "_remove_gravitational_acceleration is " << (removeGravAcc ? "true" : "false") << "\n\t" <<
00976 imuTopicName << "_queue_size is " << imuQueueSize << "\n\t" <<
00977 imuTopicName << " pose update vector is " << poseUpdateVec << "\t"<<
00978 imuTopicName << " twist update vector is " << twistUpdateVec << "\t" <<
00979 imuTopicName << " acceleration update vector is " << accelUpdateVec);
00980 }
00981 } while (moreParams);
00982
00983
00984
00985
00986
00987
00988 if(printDiagnostics_)
00989 {
00990 for(int stateVar = StateMemberX; stateVar <= StateMemberYaw; ++stateVar)
00991 {
00992 if(absPoseVarCounts[static_cast<StateMembers>(stateVar)] > 1)
00993 {
00994 std::stringstream stream;
00995 stream << absPoseVarCounts[static_cast<StateMembers>(stateVar - POSITION_OFFSET)] <<
00996 " absolute pose inputs detected for " << stateVariableNames_[stateVar] <<
00997 ". This may result in oscillations. Please ensure that your variances for each "
00998 "measured variable are set appropriately.";
00999
01000 addDiagnostic(diagnostic_msgs::DiagnosticStatus::WARN,
01001 stateVariableNames_[stateVar] + "_configuration",
01002 stream.str(),
01003 true);
01004 }
01005 else if(absPoseVarCounts[static_cast<StateMembers>(stateVar)] == 0)
01006 {
01007 if(twoDMode_ == false)
01008 {
01009 if(static_cast<StateMembers>(stateVar) == StateMemberRoll ||
01010 static_cast<StateMembers>(stateVar) == StateMemberPitch)
01011 {
01012 std::stringstream stream;
01013 stream << "two_d_mode is false, and " << stateVariableNames_[stateVar] << " is not being measured. "
01014 "This will result in unbounded error growth and erratic filter behavior.";
01015
01016 addDiagnostic(diagnostic_msgs::DiagnosticStatus::ERROR,
01017 stateVariableNames_[stateVar] + "_configuration",
01018 stream.str(),
01019 true);
01020 }
01021 }
01022
01023 if(static_cast<StateMembers>(stateVar) == StateMemberYaw)
01024 {
01025 std::stringstream stream;
01026 stream << stateVariableNames_[stateVar] << " is not being measured. This will result "
01027 "in unbounded error growth and erratic filter behavior.";
01028
01029 addDiagnostic(diagnostic_msgs::DiagnosticStatus::ERROR,
01030 stateVariableNames_[stateVar] + "_configuration",
01031 stream.str(),
01032 true);
01033 }
01034
01035 if((static_cast<StateMembers>(stateVar) == StateMemberX &&
01036 twistVarCounts[static_cast<StateMembers>(StateMemberVx)] == 0) ||
01037 (static_cast<StateMembers>(stateVar) == StateMemberY &&
01038 twistVarCounts[static_cast<StateMembers>(StateMemberVy)] == 0) ||
01039 (static_cast<StateMembers>(stateVar) == StateMemberZ &&
01040 twistVarCounts[static_cast<StateMembers>(StateMemberVz)] == 0 &&
01041 twoDMode_ == false))
01042 {
01043 std::stringstream stream;
01044 stream << "Neither " << stateVariableNames_[stateVar] << " nor its "
01045 "velocity is being measured. This will result in unbounded "
01046 "error growth and erratic filter behavior.";
01047
01048 addDiagnostic(diagnostic_msgs::DiagnosticStatus::ERROR,
01049 stateVariableNames_[stateVar] + "_configuration",
01050 stream.str(),
01051 true);
01052 }
01053
01054 }
01055 }
01056 }
01057
01058
01059 Eigen::MatrixXd processNoiseCovariance(STATE_SIZE, STATE_SIZE);
01060 processNoiseCovariance.setZero();
01061 XmlRpc::XmlRpcValue processNoiseCovarConfig;
01062
01063 if (nhLocal_.hasParam("process_noise_covariance"))
01064 {
01065 try
01066 {
01067 nhLocal_.getParam("process_noise_covariance", processNoiseCovarConfig);
01068
01069 ROS_ASSERT(processNoiseCovarConfig.getType() == XmlRpc::XmlRpcValue::TypeArray);
01070
01071 int matSize = processNoiseCovariance.rows();
01072
01074 if (processNoiseCovarConfig.size() != matSize * matSize)
01075 {
01076 if(::fabs(::sqrt(processNoiseCovarConfig.size()) - 12) < 0.1)
01077 {
01078 ROS_WARN_STREAM("Process_noise_covariance matrix should have " << matSize * matSize << " values.");
01079 matSize = 12;
01080 }
01081 else
01082 {
01083 ROS_FATAL_STREAM("Process_noise_covariance matrix must have " << matSize * matSize << " values.");
01084 }
01085 }
01087
01088 for (int i = 0; i < matSize; i++)
01089 {
01090 for (int j = 0; j < matSize; j++)
01091 {
01092 try
01093 {
01094
01095
01096
01097 std::ostringstream ostr;
01098 ostr << processNoiseCovarConfig[matSize * i + j];
01099 std::istringstream istr(ostr.str());
01100 istr >> processNoiseCovariance(i, j);
01101 }
01102 catch(XmlRpc::XmlRpcException &e)
01103 {
01104 throw e;
01105 }
01106 catch(...)
01107 {
01108 throw;
01109 }
01110 }
01111 }
01112
01113 RF_DEBUG("Process noise covariance is:\n" << processNoiseCovariance << "\n");
01114 }
01115 catch (XmlRpc::XmlRpcException &e)
01116 {
01117 ROS_ERROR_STREAM(
01118 "ERROR reading sensor config: " << e.getMessage() << " for process_noise_covariance (type: " << processNoiseCovarConfig.getType() << ")");
01119 }
01120
01121 filter_.setProcessNoiseCovariance(processNoiseCovariance);
01122 }
01123
01124
01125 Eigen::MatrixXd initialEstimateErrorCovariance(STATE_SIZE, STATE_SIZE);
01126 initialEstimateErrorCovariance.setZero();
01127 XmlRpc::XmlRpcValue estimateErrorCovarConfig;
01128
01129 if (nhLocal_.hasParam("initial_estimate_covariance"))
01130 {
01131 try
01132 {
01133 nhLocal_.getParam("initial_estimate_covariance", estimateErrorCovarConfig);
01134
01135 ROS_ASSERT(estimateErrorCovarConfig.getType() == XmlRpc::XmlRpcValue::TypeArray);
01136
01137 int matSize = initialEstimateErrorCovariance.rows();
01138
01139 for (int i = 0; i < matSize; i++)
01140 {
01141 for (int j = 0; j < matSize; j++)
01142 {
01143 try
01144 {
01145
01146
01147
01148 std::ostringstream ostr;
01149 ostr << estimateErrorCovarConfig[matSize * i + j];
01150 std::istringstream istr(ostr.str());
01151 istr >> initialEstimateErrorCovariance(i, j);
01152 }
01153 catch(XmlRpc::XmlRpcException &e)
01154 {
01155 throw e;
01156 }
01157 catch(...)
01158 {
01159 throw;
01160 }
01161 }
01162 }
01163
01164 RF_DEBUG("Initial estimate error covariance is:\n" << initialEstimateErrorCovariance << "\n");
01165 }
01166 catch (XmlRpc::XmlRpcException &e)
01167 {
01168 ROS_ERROR_STREAM(
01169 "ERROR reading initial_estimate_covariance (type: " << estimateErrorCovarConfig.getType() << "): " << e.getMessage());
01170 }
01171 catch(...)
01172 {
01173 ROS_ERROR_STREAM(
01174 "ERROR reading initial_estimate_covariance (type: " << estimateErrorCovarConfig.getType() << ")");
01175 }
01176
01177 filter_.setEstimateErrorCovariance(initialEstimateErrorCovariance);
01178 }
01179 }
01180
01181 template<typename T>
01182 void RosFilter<T>::odometryCallback(const nav_msgs::Odometry::ConstPtr &msg,
01183 const std::string &topicName)
01184 {
01185
01186
01187 if(msg->header.stamp <= lastSetPoseTime_)
01188 {
01189 return;
01190 }
01191
01192 RF_DEBUG("------ RosFilter::odometryCallback (" << topicName << ") ------\n" <<
01193 "Odometry message:\n" << *msg);
01194
01195 std::string odomPoseTopicName = topicName + "_pose";
01196 if(poseMessageFilters_.count(odomPoseTopicName) > 0)
01197 {
01198
01199 geometry_msgs::PoseWithCovarianceStamped *posPtr = new geometry_msgs::PoseWithCovarianceStamped();
01200 posPtr->header = msg->header;
01201 posPtr->pose = msg->pose;
01202
01203 geometry_msgs::PoseWithCovarianceStampedConstPtr pptr(posPtr);
01204 poseMessageFilters_[odomPoseTopicName]->add(pptr);
01205 }
01206
01207 std::string odomTwistTopicName = topicName + "_twist";
01208 if(twistMessageFilters_.count(odomTwistTopicName) > 0)
01209 {
01210
01211 geometry_msgs::TwistWithCovarianceStamped *twistPtr = new geometry_msgs::TwistWithCovarianceStamped();
01212 twistPtr->header = msg->header;
01213 twistPtr->header.frame_id = msg->child_frame_id;
01214 twistPtr->twist = msg->twist;
01215
01216
01217 geometry_msgs::TwistWithCovarianceStampedConstPtr tptr(twistPtr);
01218 twistMessageFilters_[odomTwistTopicName]->add(tptr);
01219 }
01220
01221 RF_DEBUG("\n----- /RosFilter::odometryCallback (" << topicName << ") ------\n");
01222 }
01223
01224 template<typename T>
01225 void RosFilter<T>::poseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr &msg,
01226 const std::string &topicName,
01227 const std::string &targetFrame,
01228 const std::vector<int> &updateVector,
01229 const bool differential,
01230 const bool relative,
01231 const bool imuData,
01232 const double mahalanobisThresh)
01233 {
01234
01235
01236 if(msg->header.stamp <= lastSetPoseTime_)
01237 {
01238 return;
01239 }
01240
01241 RF_DEBUG("------ RosFilter::poseCallback (" << topicName << ") ------\n" <<
01242 "Pose message:\n" << *msg);
01243
01244
01245 if (lastMessageTimes_.count(topicName) == 0)
01246 {
01247 lastMessageTimes_.insert(std::pair<std::string, ros::Time>(topicName, msg->header.stamp));
01248 }
01249
01250
01251 if (msg->header.stamp >= lastMessageTimes_[topicName])
01252 {
01253 RF_DEBUG("Update vector for " << topicName << " is:\n" << updateVector);
01254
01255 Eigen::VectorXd measurement(STATE_SIZE);
01256 Eigen::MatrixXd measurementCovariance(STATE_SIZE, STATE_SIZE);
01257
01258 measurement.setZero();
01259 measurementCovariance.setZero();
01260
01261
01262 if (updateVector[StateMemberX] || updateVector[StateMemberY] || updateVector[StateMemberZ] ||
01263 updateVector[StateMemberRoll] || updateVector[StateMemberPitch] || updateVector[StateMemberYaw])
01264 {
01265 std::vector<int> updateVectorCorrected = updateVector;
01266
01267
01268 if (preparePose(msg, topicName, targetFrame, differential, relative, imuData, updateVectorCorrected, measurement, measurementCovariance))
01269 {
01270
01271
01272 enqueueMeasurement(topicName, measurement, measurementCovariance, updateVectorCorrected, mahalanobisThresh, msg->header.stamp);
01273
01274 RF_DEBUG("Enqueued new measurement for " << topicName << "\n");
01275 }
01276 else
01277 {
01278 RF_DEBUG("Did *not* enqueue measurement for " << topicName << "\n");
01279 }
01280 }
01281 else
01282 {
01283 RF_DEBUG("Update vector for " << topicName << " is such that none of its state variables will be updated\n");
01284 }
01285
01286 lastMessageTimes_[topicName] = msg->header.stamp;
01287
01288 RF_DEBUG("Last message time for " << topicName << " is now " << lastMessageTimes_[topicName] << "\n");
01289 }
01290 else
01291 {
01292 RF_DEBUG("Message is too old. Last message time for " << topicName << " is "
01293 << lastMessageTimes_[topicName] << ", current message time is "
01294 << msg->header.stamp << ".\n");
01295 }
01296
01297 RF_DEBUG("\n----- /RosFilter::poseCallback (" << topicName << ") ------\n");
01298 }
01299
01300 template<typename T>
01301 void RosFilter<T>::run()
01302 {
01303 ros::Time::init();
01304
01305 loadParams();
01306
01307 if(printDiagnostics_)
01308 {
01309 diagnosticUpdater_.add("Filter diagnostic updater", this, &RosFilter<T>::aggregateDiagnostics);
01310 }
01311
01312
01313 double minFrequency = frequency_ - 2;
01314 double maxFrequency = frequency_ + 2;
01315 diagnostic_updater::HeaderlessTopicDiagnostic freqDiag("odometry/filtered",
01316 diagnosticUpdater_,
01317 diagnostic_updater::FrequencyStatusParam(&minFrequency,
01318 &maxFrequency,
01319 0.1, 10));
01320
01321
01322
01323 tf::StampedTransform mapOdomTrans;
01324 tf::StampedTransform odomBaseLinkTrans;
01325 geometry_msgs::TransformStamped mapOdomTransMsg;
01326 ros::Time curTime;
01327 ros::Time lastDiagTime = ros::Time::now();
01328
01329
01330 tf::transformTFToMsg(tf::Transform::getIdentity(), worldBaseLinkTransMsg_.transform);
01331 tf::transformTFToMsg(tf::Transform::getIdentity(), mapOdomTransMsg.transform);
01332
01333
01334 ros::Publisher positionPub = nh_.advertise<nav_msgs::Odometry>("odometry/filtered", 20);
01335 tf::TransformBroadcaster worldTransformBroadcaster;
01336
01337 ros::Rate loop_rate(frequency_);
01338
01339 while (ros::ok())
01340 {
01341
01342 nav_msgs::Odometry filteredPosition;
01343
01344 if (getFilteredOdometryMessage(filteredPosition))
01345 {
01346 worldBaseLinkTransMsg_.header.stamp = filteredPosition.header.stamp + tfTimeOffset_;
01347 worldBaseLinkTransMsg_.header.frame_id = filteredPosition.header.frame_id;
01348 worldBaseLinkTransMsg_.child_frame_id = filteredPosition.child_frame_id;
01349
01350 worldBaseLinkTransMsg_.transform.translation.x = filteredPosition.pose.pose.position.x;
01351 worldBaseLinkTransMsg_.transform.translation.y = filteredPosition.pose.pose.position.y;
01352 worldBaseLinkTransMsg_.transform.translation.z = filteredPosition.pose.pose.position.z;
01353 worldBaseLinkTransMsg_.transform.rotation = filteredPosition.pose.pose.orientation;
01354
01355
01356
01357 if(filteredPosition.header.frame_id == odomFrameId_)
01358 {
01359 worldTransformBroadcaster.sendTransform(worldBaseLinkTransMsg_);
01360 }
01361 else if(filteredPosition.header.frame_id == mapFrameId_)
01362 {
01363 try
01364 {
01365 tf::StampedTransform worldBaseLinkTrans;
01366 tf::transformStampedMsgToTF(worldBaseLinkTransMsg_, worldBaseLinkTrans);
01367
01368 tfListener_.lookupTransform(baseLinkFrameId_, odomFrameId_, ros::Time(0), odomBaseLinkTrans);
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 mapOdomTrans.mult(worldBaseLinkTrans, odomBaseLinkTrans);
01389
01390 tf::transformStampedTFToMsg(mapOdomTrans, mapOdomTransMsg);
01391 mapOdomTransMsg.header.stamp = filteredPosition.header.stamp + tfTimeOffset_;
01392 mapOdomTransMsg.header.frame_id = mapFrameId_;
01393 mapOdomTransMsg.child_frame_id = odomFrameId_;
01394
01395 worldTransformBroadcaster.sendTransform(mapOdomTransMsg);
01396 }
01397 catch(...)
01398 {
01399 ROS_ERROR_STREAM("Could not obtain transform from " << odomFrameId_ << "->" << baseLinkFrameId_);
01400 }
01401 }
01402 else
01403 {
01404 ROS_ERROR_STREAM("Odometry message frame_id was " << filteredPosition.header.frame_id <<
01405 ", expected " << mapFrameId_ << " or " << odomFrameId_);
01406 }
01407
01408
01409 positionPub.publish(filteredPosition);
01410
01411 if(printDiagnostics_)
01412 {
01413 freqDiag.tick();
01414 }
01415 }
01416
01417
01418
01419 ros::spinOnce();
01420
01421
01422 ros::Time curTime = ros::Time::now();
01423 integrateMeasurements(ros::Time::now().toSec());
01424
01425
01426
01427
01428
01429 double diagDuration = (curTime - lastDiagTime).toSec();
01430 if(printDiagnostics_ && (diagDuration >= diagnosticUpdater_.getPeriod() || diagDuration < 0.0))
01431 {
01432 diagnosticUpdater_.force_update();
01433 lastDiagTime = curTime;
01434 }
01435
01436 if(!loop_rate.sleep())
01437 {
01438 ROS_WARN_STREAM("Failed to meet update rate! Try decreasing the rate, limiting sensor output frequency, or limiting the number of sensors.");
01439 }
01440 }
01441 }
01442
01443 template<typename T>
01444 void RosFilter<T>::setPoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr &msg)
01445 {
01446 RF_DEBUG("------ RosFilter::setPoseCallback ------\nPose message:\n" << *msg);
01447
01448 std::string topicName("setPose");
01449
01450
01451 initialMeasurements_.clear();
01452 previousMeasurements_.clear();
01453 previousMeasurementCovariances_.clear();
01454
01455
01456
01457 while(!measurementQueue_.empty())
01458 {
01459 measurementQueue_.pop();
01460 }
01461
01462
01463
01464 lastSetPoseTime_ = msg->header.stamp;
01465
01466
01467 Eigen::VectorXd measurement(STATE_SIZE);
01468 Eigen::MatrixXd measurementCovariance(STATE_SIZE, STATE_SIZE);
01469 std::vector<int> updateVector(STATE_SIZE, true);
01470
01471
01472 measurement.setZero();
01473
01474
01475 measurementCovariance.setIdentity();
01476 measurementCovariance *= 1e-6;
01477
01478
01479
01480 preparePose(msg, topicName, worldFrameId_, false, false, false, updateVector, measurement, measurementCovariance);
01481
01482
01483 filter_.setState(measurement);
01484 filter_.setEstimateErrorCovariance(measurementCovariance);
01485
01486 filter_.setLastMeasurementTime(ros::Time::now().toSec());
01487 filter_.setLastUpdateTime(ros::Time::now().toSec());
01488
01489 RF_DEBUG("\n------ /RosFilter::setPoseCallback ------\n");
01490 }
01491
01492 template<typename T>
01493 bool RosFilter<T>::setPoseSrvCallback(robot_localization::SetPose::Request& request,
01494 robot_localization::SetPose::Response&)
01495 {
01496 geometry_msgs::PoseWithCovarianceStamped::Ptr msg;
01497 msg = boost::make_shared<geometry_msgs::PoseWithCovarianceStamped>(request.pose);
01498 setPoseCallback(msg);
01499
01500 return true;
01501 }
01502
01503 template<typename T>
01504 std::string RosFilter<T>::tfFailureReasonString(const tf::FilterFailureReason reason)
01505 {
01506 std::string retVal;
01507
01508 switch(reason)
01509 {
01510 case tf::filter_failure_reasons::OutTheBack:
01511 retVal = std::string("The timestamp on the message is more than the cache length earlier than the newest data in the transform cache");
01512 break;
01513 case tf::filter_failure_reasons::EmptyFrameID:
01514 retVal = std::string("The message frame_id is empty");
01515 break;
01516 case tf::filter_failure_reasons::Unknown:
01517 default:
01518 retVal = std::string("No transform exists from source to target frame");
01519 break;
01520 }
01521
01522 return retVal;
01523 }
01524
01525 template<typename T>
01526 void RosFilter<T>::transformImuFailureCallback(const sensor_msgs::Imu::ConstPtr &msg,
01527 const tf::FilterFailureReason reason,
01528 const std::string &topicName,
01529 const std::string &targetFrame)
01530 {
01531 std::stringstream stream;
01532 std::string warning;
01533
01534 stream << "WARNING: failed to transform from " << msg->header.frame_id <<
01535 "->" << targetFrame << " for " << topicName << " message received at " <<
01536 msg->header.stamp << ". " << tfFailureReasonString(reason) << ".\n";
01537 warning = stream.str();
01538
01539 ROS_WARN_STREAM_THROTTLE(2.0, warning);
01540 RF_DEBUG(warning);
01541 }
01542
01543 template<typename T>
01544 void RosFilter<T>::transformPoseFailureCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr &msg,
01545 const tf::FilterFailureReason reason,
01546 const std::string &topicName,
01547 const std::string &targetFrame)
01548 {
01549 std::stringstream stream;
01550 std::string warning;
01551
01552 stream << "WARNING: failed to transform from " << msg->header.frame_id <<
01553 "->" << targetFrame << " for " << topicName << " message received at " <<
01554 msg->header.stamp << ". " << tfFailureReasonString(reason) << ".\n";
01555 warning = stream.str();
01556
01557 ROS_WARN_STREAM_THROTTLE(2.0, warning);
01558 RF_DEBUG(warning);
01559 }
01560
01561 template<typename T>
01562 void RosFilter<T>::transformTwistFailureCallback(const geometry_msgs::TwistWithCovarianceStamped::ConstPtr &msg,
01563 const tf::FilterFailureReason reason,
01564 const std::string &topicName,
01565 const std::string &targetFrame)
01566 {
01567 std::stringstream stream;
01568 std::string warning;
01569
01570 stream << "WARNING: failed to transform from " << msg->header.frame_id <<
01571 "->" << targetFrame << " for " << topicName << " message received at " <<
01572 msg->header.stamp << ". " << tfFailureReasonString(reason) << ".\n";
01573 warning = stream.str();
01574
01575 ROS_WARN_STREAM_THROTTLE(2.0, warning);
01576 RF_DEBUG(warning);
01577 }
01578
01579 template<typename T>
01580 void RosFilter<T>::twistCallback(const geometry_msgs::TwistWithCovarianceStamped::ConstPtr &msg,
01581 const std::string &topicName,
01582 const std::string &targetFrame,
01583 const std::vector<int> &updateVector,
01584 const double mahalanobisThresh)
01585 {
01586
01587
01588 if(msg->header.stamp <= lastSetPoseTime_)
01589 {
01590 return;
01591 }
01592
01593 RF_DEBUG("------ RosFilter::twistCallback (" << topicName << ") ------\n"
01594 "Twist message:\n" << *msg);
01595
01596 if (lastMessageTimes_.count(topicName) == 0)
01597 {
01598 lastMessageTimes_.insert(std::pair<std::string, ros::Time>(topicName, msg->header.stamp));
01599 }
01600
01601
01602 if (msg->header.stamp >= lastMessageTimes_[topicName])
01603 {
01604 RF_DEBUG("Update vector for " << topicName << " is:\n" << updateVector);
01605
01606 Eigen::VectorXd measurement(STATE_SIZE);
01607 Eigen::MatrixXd measurementCovariance(STATE_SIZE, STATE_SIZE);
01608
01609 measurement.setZero();
01610 measurementCovariance.setZero();
01611
01612
01613 if (updateVector[StateMemberVx] || updateVector[StateMemberVy] || updateVector[StateMemberVz] ||
01614 updateVector[StateMemberVroll] || updateVector[StateMemberVpitch] || updateVector[StateMemberVyaw])
01615 {
01616 std::vector<int> updateVectorCorrected = updateVector;
01617
01618
01619 if (prepareTwist(msg, topicName, targetFrame, updateVectorCorrected, measurement, measurementCovariance))
01620 {
01621
01622
01623 enqueueMeasurement(topicName, measurement, measurementCovariance, updateVectorCorrected, mahalanobisThresh, msg->header.stamp);
01624
01625 RF_DEBUG("Enqueued new measurement for " << topicName << "_twist\n");
01626 }
01627 else
01628 {
01629 RF_DEBUG("Did *not* enqueue measurement for " << topicName << "_twist\n");
01630 }
01631 }
01632 else
01633 {
01634 RF_DEBUG("Update vector for " << topicName << " is such that none of its state variables will be updated\n");
01635 }
01636
01637 lastMessageTimes_[topicName] = msg->header.stamp;
01638
01639 RF_DEBUG("Last message time for " << topicName << " is now " << lastMessageTimes_[topicName] << "\n");
01640 }
01641 else
01642 {
01643 RF_DEBUG("Message is too old. Last message time for " << topicName <<
01644 " is " << lastMessageTimes_[topicName] << ", current message time is " <<
01645 msg->header.stamp << ".\n");
01646 }
01647
01648 RF_DEBUG("\n----- /RosFilter::twistCallback (" << topicName << ") ------\n");
01649 }
01650
01651 template<typename T>
01652 void RosFilter<T>::addDiagnostic(const int errLevel,
01653 const std::string &topicAndClass,
01654 const std::string &message,
01655 const bool staticDiag)
01656 {
01657 if(staticDiag)
01658 {
01659 staticDiagnostics_[topicAndClass] = message;
01660 staticDiagErrorLevel_ = std::max(staticDiagErrorLevel_, errLevel);
01661 }
01662 else
01663 {
01664 dynamicDiagnostics_[topicAndClass] = message;
01665 dynamicDiagErrorLevel_ = std::max(dynamicDiagErrorLevel_, errLevel);
01666 }
01667 }
01668
01669 template<typename T>
01670 void RosFilter<T>::aggregateDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &wrapper)
01671 {
01672 wrapper.clear();
01673 wrapper.clearSummary();
01674
01675 int maxErrLevel = std::max(staticDiagErrorLevel_, dynamicDiagErrorLevel_);
01676
01677
01678 switch(maxErrLevel)
01679 {
01680 case diagnostic_msgs::DiagnosticStatus::ERROR:
01681 wrapper.summary(maxErrLevel,
01682 "Erroneous data or settings detected for a robot_localization state estimation node.");
01683 break;
01684 case diagnostic_msgs::DiagnosticStatus::WARN:
01685 wrapper.summary(maxErrLevel,
01686 "Potentially erroneous data or settings detected for a robot_localization state estimation node.");
01687 break;
01688 case diagnostic_msgs::DiagnosticStatus::OK:
01689 wrapper.summary(maxErrLevel,
01690 "The robot_localization state estimation node appears to be functioning properly.");
01691 break;
01692 default:
01693 break;
01694 }
01695
01696
01697 for(std::map<std::string, std::string>::iterator diagIt = staticDiagnostics_.begin();
01698 diagIt != staticDiagnostics_.end();
01699 ++diagIt)
01700 {
01701 wrapper.add(diagIt->first, diagIt->second);
01702 }
01703
01704
01705 for(std::map<std::string, std::string>::iterator diagIt = dynamicDiagnostics_.begin();
01706 diagIt != dynamicDiagnostics_.end();
01707 ++diagIt)
01708 {
01709 wrapper.add(diagIt->first, diagIt->second);
01710 }
01711 dynamicDiagnostics_.clear();
01712
01713
01714 dynamicDiagErrorLevel_ = diagnostic_msgs::DiagnosticStatus::OK;
01715 }
01716
01717 template<typename T>
01718 void RosFilter<T>::copyCovariance(const double *arr,
01719 Eigen::MatrixXd &covariance,
01720 const std::string &topicName,
01721 const std::vector<int> &updateVector,
01722 const size_t offset,
01723 const size_t dimension)
01724 {
01725 for (size_t i = 0; i < dimension; i++)
01726 {
01727 for (size_t j = 0; j < dimension; j++)
01728 {
01729 covariance(i, j) = arr[dimension * i + j];
01730
01731 if(printDiagnostics_)
01732 {
01733 std::string iVar = stateVariableNames_[offset + i];
01734
01735 if(covariance(i, j) > 1e3 && (updateVector[offset + i] || updateVector[offset + j]))
01736 {
01737 std::string jVar = stateVariableNames_[offset + j];
01738
01739 std::stringstream stream;
01740 stream << "The covariance at position (" << dimension * i + j << "), which corresponds to " <<
01741 (i == j ? iVar + " variance" : iVar + " and " + jVar + " covariance") <<
01742 ", the value is extremely large (" << covariance(i, j) << "), but the update vector for " <<
01743 (i == j ? iVar : iVar + " and/or " + jVar) << " is set to true. This may produce undesirable results.";
01744
01745 addDiagnostic(diagnostic_msgs::DiagnosticStatus::WARN,
01746 topicName + "_covariance",
01747 stream.str(),
01748 false);
01749 }
01750 else if(updateVector[i] && i == j && covariance(i, j) == 0)
01751 {
01752 std::stringstream stream;
01753 stream << "The covariance at position (" << dimension * i + j << "), which corresponds to " <<
01754 iVar << " variance, was zero. This will be replaced with "
01755 "a small value to maintain filter stability, but should be corrected at the message origin node.";
01756
01757 addDiagnostic(diagnostic_msgs::DiagnosticStatus::WARN,
01758 topicName + "_covariance",
01759 stream.str(),
01760 false);
01761 }
01762 else if(updateVector[i] && i == j && covariance(i, j) < 0)
01763 {
01764 std::stringstream stream;
01765 stream << "The covariance at position (" << dimension * i + j <<
01766 "), which corresponds to " << iVar << " variance, was negative. This will be replaced with "
01767 "a small positive value to maintain filter stability, but should be corrected at the message origin node.";
01768
01769 addDiagnostic(diagnostic_msgs::DiagnosticStatus::WARN,
01770 topicName + "_covariance",
01771 stream.str(),
01772 false);
01773 }
01774 }
01775 }
01776 }
01777 }
01778
01779 template<typename T>
01780 void RosFilter<T>::copyCovariance(const Eigen::MatrixXd &covariance,
01781 double *arr,
01782 const size_t dimension)
01783 {
01784 for (size_t i = 0; i < dimension; i++)
01785 {
01786 for (size_t j = 0; j < dimension; j++)
01787 {
01788 arr[dimension * i + j] = covariance(i, j);
01789 }
01790 }
01791 }
01792
01793 template<typename T>
01794 std::vector<int> RosFilter<T>::loadUpdateConfig(const std::string &topicName)
01795 {
01796 XmlRpc::XmlRpcValue topicConfig;
01797 std::vector<int> updateVector(STATE_SIZE, 0);
01798 std::string topicConfigName = topicName + "_config";
01799
01800 try
01801 {
01802 nhLocal_.getParam(topicConfigName, topicConfig);
01803
01804 ROS_ASSERT(topicConfig.getType() == XmlRpc::XmlRpcValue::TypeArray);
01805
01806 if(topicConfig.size() != STATE_SIZE)
01807 {
01808 ROS_WARN_STREAM("Configuration vector for " << topicConfigName << " should have 15 entries.");
01809 }
01810
01811 for (int i = 0; i < topicConfig.size(); i++)
01812 {
01813
01814
01815
01816 updateVector[i] = static_cast<int>(static_cast<bool>(topicConfig[i]));
01817 }
01818 }
01819 catch (XmlRpc::XmlRpcException &e)
01820 {
01821 ROS_FATAL_STREAM("Could not read sensor update configuration for topic " << topicName <<
01822 " (type: " << topicConfig.getType() << ", expected: " << XmlRpc::XmlRpcValue::TypeArray
01823 << "). Error was " << e.getMessage() << "\n");
01824 }
01825
01826 return updateVector;
01827 }
01828
01829 template<typename T>
01830 bool RosFilter<T>::lookupTransformSafe(const std::string &targetFrame,
01831 const std::string &sourceFrame,
01832 const ros::Time &time,
01833 tf::StampedTransform &targetFrameTrans)
01834 {
01835 bool retVal = true;
01836
01837
01838 try
01839 {
01840 tfListener_.lookupTransform(targetFrame, sourceFrame, time, targetFrameTrans);
01841 }
01842 catch (tf::TransformException &ex)
01843 {
01844 RF_DEBUG("WARNING: Could not obtain transform from " << sourceFrame <<
01845 " to " << targetFrame << ". Error was " << ex.what());
01846
01847
01848
01849
01850 try
01851 {
01852 tfListener_.lookupTransform(targetFrame, sourceFrame, ros::Time(0), targetFrameTrans);
01853
01854 ROS_WARN_STREAM_THROTTLE(2.0, "Transform from " << sourceFrame << " to " << targetFrame <<
01855 " was unavailable for the time requested. Using latest instead.\n");
01856 }
01857 catch(tf::TransformException &ex)
01858 {
01859 ROS_WARN_STREAM_THROTTLE(2.0, "Could not obtain transform from " << sourceFrame <<
01860 " to " << targetFrame << ". Error was " << ex.what() << "\n");
01861
01862 retVal = false;
01863 }
01864 }
01865
01866
01867
01868
01869 if(!retVal)
01870 {
01871 if(targetFrame == sourceFrame)
01872 {
01873 targetFrameTrans.setIdentity();
01874 retVal = true;
01875 }
01876 }
01877
01878 return retVal;
01879 }
01880
01881 template<typename T>
01882 bool RosFilter<T>::prepareAcceleration(const sensor_msgs::Imu::ConstPtr &msg,
01883 const std::string &topicName,
01884 const std::string &targetFrame,
01885 std::vector<int> &updateVector,
01886 Eigen::VectorXd &measurement,
01887 Eigen::MatrixXd &measurementCovariance)
01888 {
01889 RF_DEBUG("------ RosFilter::prepareAcceleration (" << topicName << ") ------\n");
01890
01891
01892 tf::Vector3 accTmp(msg->linear_acceleration.x,
01893 msg->linear_acceleration.y,
01894 msg->linear_acceleration.z);
01895
01896
01897 std::string msgFrame = (msg->header.frame_id == "" ? baseLinkFrameId_ : msg->header.frame_id);
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907 tf::Matrix3x3 maskAcc(updateVector[StateMemberAx], 0, 0,
01908 0, updateVector[StateMemberAy], 0,
01909 0, 0, updateVector[StateMemberAz]);
01910
01911
01912 Eigen::MatrixXd covarianceRotated(ACCELERATION_SIZE, ACCELERATION_SIZE);
01913 covarianceRotated.setZero();
01914
01915 this->copyCovariance(&(msg->linear_acceleration_covariance[0]), covarianceRotated, topicName, updateVector, POSITION_A_OFFSET, ACCELERATION_SIZE);
01916
01917 RF_DEBUG("Original measurement as tf object: " << accTmp <<
01918 "\nOriginal update vector:\n" << updateVector <<
01919 "\nOriginal covariance matrix:\n" << covarianceRotated << "\n");
01920
01921
01922
01923
01924 tf::StampedTransform targetFrameTrans;
01925 bool canTransform = lookupTransformSafe(targetFrame, msgFrame, msg->header.stamp, targetFrameTrans);
01926
01927 if(canTransform)
01928 {
01929
01930
01931 if(removeGravitationalAcc_[topicName])
01932 {
01933 tf::Vector3 normAcc(0, 0, 9.80665);
01934 tf::Quaternion curAttitude;
01935 tf::Transform trans;
01936 tf::quaternionMsgToTF(msg->orientation, curAttitude);
01937 trans.setRotation(curAttitude);
01938 tf::Vector3 rotNorm = trans.getBasis().inverse() * normAcc;
01939 accTmp.setX(accTmp.getX() - rotNorm.getX());
01940 accTmp.setY(accTmp.getY() - rotNorm.getY());
01941 accTmp.setZ(accTmp.getZ() - rotNorm.getZ());
01942
01943 RF_DEBUG("Orientation is " << curAttitude <<
01944 "Acceleration due to gravity is " << rotNorm <<
01945 "After removing acceleration due to gravity, acceleration is " << accTmp << "\n");
01946 }
01947
01948
01949
01950
01951
01952
01953
01954 accTmp = targetFrameTrans.getBasis() * accTmp;
01955 maskAcc = targetFrameTrans.getBasis() * maskAcc;
01956
01957
01958 updateVector[StateMemberAx] = static_cast<int>(maskAcc.getRow(StateMemberAx - POSITION_A_OFFSET).length() >= 1e-6);
01959 updateVector[StateMemberAy] = static_cast<int>(maskAcc.getRow(StateMemberAy - POSITION_A_OFFSET).length() >= 1e-6);
01960 updateVector[StateMemberAz] = static_cast<int>(maskAcc.getRow(StateMemberAz - POSITION_A_OFFSET).length() >= 1e-6);
01961
01962 RF_DEBUG(msg->header.frame_id << "->" << targetFrame << " transform:\n" << targetFrameTrans <<
01963 "\nAfter applying transform to " << targetFrame << ", update vector is:\n" << updateVector <<
01964 "\nAfter applying transform to " << targetFrame << ", measurement is:\n" << accTmp << "\n");
01965
01966
01967
01968
01969
01970 tf::Matrix3x3 rot(targetFrameTrans.getRotation());
01971 Eigen::MatrixXd rot3d(ACCELERATION_SIZE, ACCELERATION_SIZE);
01972 rot3d.setIdentity();
01973
01974 for(size_t rInd = 0; rInd < ACCELERATION_SIZE; ++rInd)
01975 {
01976 rot3d(rInd, 0) = rot.getRow(rInd).getX();
01977 rot3d(rInd, 1) = rot.getRow(rInd).getY();
01978 rot3d(rInd, 2) = rot.getRow(rInd).getZ();
01979 }
01980
01981
01982 covarianceRotated = rot3d * covarianceRotated.eval() * rot3d.transpose();
01983
01984 RF_DEBUG("Transformed covariance is \n" << covarianceRotated << "\n");
01985
01986
01987 measurement(StateMemberAx) = accTmp.getX();
01988 measurement(StateMemberAy) = accTmp.getY();
01989 measurement(StateMemberAz) = accTmp.getZ();
01990
01991
01992 measurementCovariance.block(POSITION_A_OFFSET, POSITION_A_OFFSET, ACCELERATION_SIZE, ACCELERATION_SIZE) = covarianceRotated.block(0, 0, ACCELERATION_SIZE, ACCELERATION_SIZE);
01993
01994
01995 if(twoDMode_)
01996 {
01997 forceTwoD(measurement, measurementCovariance, updateVector);
01998 }
01999 }
02000 else
02001 {
02002 RF_DEBUG("Could not transform measurement into " << targetFrame << ". Ignoring...\n");
02003 }
02004
02005 RF_DEBUG("\n----- /RosFilter::prepareAcceleration(" << topicName << ") ------\n");
02006
02007 return canTransform;
02008 }
02009
02010 template<typename T>
02011 bool RosFilter<T>::preparePose(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr &msg,
02012 const std::string &topicName,
02013 const std::string &targetFrame,
02014 const bool differential,
02015 const bool relative,
02016 const bool imuData,
02017 std::vector<int> &updateVector,
02018 Eigen::VectorXd &measurement,
02019 Eigen::MatrixXd &measurementCovariance)
02020 {
02021 bool retVal = false;
02022
02023 RF_DEBUG("------ RosFilter::preparePose (" << topicName << ") ------\n");
02024
02025
02026 tf::Stamped<tf::Pose> poseTmp;
02027
02028
02029 tf::Transform curMeasurement;
02030
02031
02032
02033
02034 std::string finalTargetFrame;
02035 if(targetFrame == "" && msg->header.frame_id == "")
02036 {
02037
02038
02039 finalTargetFrame = worldFrameId_;
02040 }
02041 else if(targetFrame == "")
02042 {
02043
02044
02045 finalTargetFrame = msg->header.frame_id;
02046 }
02047 else
02048 {
02049
02050 finalTargetFrame = targetFrame;
02051 }
02052
02053 RF_DEBUG("Final target frame for " << topicName << " is " << finalTargetFrame << "\n");
02054
02055 poseTmp.frame_id_ = msg->header.frame_id;
02056 poseTmp.stamp_ = msg->header.stamp;
02057
02058
02059 poseTmp.setOrigin(tf::Vector3(msg->pose.pose.position.x,
02060 msg->pose.pose.position.y,
02061 msg->pose.pose.position.z));
02062
02063 tf::Quaternion orientation;
02064
02065
02066 if(msg->pose.pose.orientation.x == 0 && msg->pose.pose.orientation.y == 0 &&
02067 msg->pose.pose.orientation.z == 0 && msg->pose.pose.orientation.w == 0)
02068 {
02069 orientation.setValue(0.0, 0.0, 0.0, 1.0);
02070
02071 if(updateVector[StateMemberRoll] || updateVector[StateMemberPitch] || updateVector[StateMemberYaw])
02072 {
02073 std::stringstream stream;
02074 stream << "The " << topicName << " message contains an invalid orientation quaternion, " <<
02075 "but its configuration is such that orientation data is being used. Correcting...";
02076
02077 addDiagnostic(diagnostic_msgs::DiagnosticStatus::WARN,
02078 topicName + "_orientation",
02079 stream.str(),
02080 false);
02081 }
02082 }
02083 else
02084 {
02085 tf::quaternionMsgToTF(msg->pose.pose.orientation, orientation);
02086 }
02087
02088
02089 poseTmp.setRotation(orientation);
02090
02091
02092 tf::StampedTransform targetFrameTrans;
02093 bool canTransform = lookupTransformSafe(finalTargetFrame,
02094 poseTmp.frame_id_,
02095 poseTmp.stamp_,
02096 targetFrameTrans);
02097
02098
02099 if(canTransform)
02100 {
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112 tf::Matrix3x3 maskPosition(updateVector[StateMemberX], 0, 0,
02113 0, updateVector[StateMemberY], 0,
02114 0, 0, updateVector[StateMemberZ]);
02115
02116 tf::Matrix3x3 maskOrientation(updateVector[StateMemberRoll], 0, 0,
02117 0, updateVector[StateMemberPitch], 0,
02118 0, 0, updateVector[StateMemberYaw]);
02119
02120 if(imuData)
02121 {
02122
02123
02124
02125
02126
02127
02128
02129 double dummy, yaw;
02130 targetFrameTrans.getBasis().getRPY(dummy, dummy, yaw);
02131 tf::Matrix3x3 transTmp;
02132 transTmp.setRPY(0.0, 0.0, yaw);
02133
02134 maskPosition = transTmp * maskPosition;
02135 maskOrientation = transTmp * maskOrientation;
02136 }
02137 else
02138 {
02139 maskPosition = targetFrameTrans.getBasis() * maskPosition;
02140 maskOrientation = targetFrameTrans.getBasis() * maskOrientation;
02141 }
02142
02143
02144
02145 updateVector[StateMemberX] = static_cast<int>(maskPosition.getRow(StateMemberX - POSITION_OFFSET).length() >= 1e-6);
02146 updateVector[StateMemberY] = static_cast<int>(maskPosition.getRow(StateMemberY - POSITION_OFFSET).length() >= 1e-6);
02147 updateVector[StateMemberZ] = static_cast<int>(maskPosition.getRow(StateMemberZ - POSITION_OFFSET).length() >= 1e-6);
02148 updateVector[StateMemberRoll] = static_cast<int>(maskOrientation.getRow(StateMemberRoll - ORIENTATION_OFFSET).length() >= 1e-6);
02149 updateVector[StateMemberPitch] = static_cast<int>(maskOrientation.getRow(StateMemberPitch - ORIENTATION_OFFSET).length() >= 1e-6);
02150 updateVector[StateMemberYaw] = static_cast<int>(maskOrientation.getRow(StateMemberYaw - ORIENTATION_OFFSET).length() >= 1e-6);
02151
02152
02153
02154 Eigen::MatrixXd covariance(POSE_SIZE, POSE_SIZE);
02155 covariance.setZero();
02156 copyCovariance(&(msg->pose.covariance[0]), covariance, topicName, updateVector, POSITION_OFFSET, POSE_SIZE);
02157
02158
02159
02160
02161 tf::Matrix3x3 rot;
02162 Eigen::MatrixXd rot6d(POSE_SIZE, POSE_SIZE);
02163 rot6d.setIdentity();
02164 Eigen::MatrixXd covarianceRotated;
02165
02166 if(imuData)
02167 {
02168
02169 double dummy, yaw;
02170 targetFrameTrans.getBasis().getRPY(dummy, dummy, yaw);
02171 rot.setRPY(0.0, 0.0, yaw);
02172 }
02173 else
02174 {
02175 rot.setRotation(targetFrameTrans.getRotation());
02176 }
02177
02178 for(size_t rInd = 0; rInd < POSITION_SIZE; ++rInd)
02179 {
02180 rot6d(rInd, 0) = rot.getRow(rInd).getX();
02181 rot6d(rInd, 1) = rot.getRow(rInd).getY();
02182 rot6d(rInd, 2) = rot.getRow(rInd).getZ();
02183 rot6d(rInd+POSITION_SIZE, 3) = rot.getRow(rInd).getX();
02184 rot6d(rInd+POSITION_SIZE, 4) = rot.getRow(rInd).getY();
02185 rot6d(rInd+POSITION_SIZE, 5) = rot.getRow(rInd).getZ();
02186 }
02187
02188
02189 covarianceRotated = rot6d * covariance * rot6d.transpose();
02190
02191 RF_DEBUG("After rotating into the " << finalTargetFrame << " frame, covariance is \n" << covarianceRotated << "\n");
02192
02193
02194
02195
02196
02197
02198
02199
02200
02201 if(imuData)
02202 {
02203
02204
02205 double rollOffset = 0;
02206 double pitchOffset = 0;
02207 double yawOffset = 0;
02208 double roll = 0;
02209 double pitch = 0;
02210 double yaw = 0;
02211 RosFilterUtilities::quatToRPY(targetFrameTrans.getRotation(), rollOffset, pitchOffset, yawOffset);
02212 RosFilterUtilities::quatToRPY(poseTmp.getRotation(), roll, pitch, yaw);
02213
02214
02215 tf::Vector3 rpyAngles(FilterUtilities::clampRotation(roll - rollOffset),
02216 FilterUtilities::clampRotation(pitch - pitchOffset),
02217 FilterUtilities::clampRotation(yaw - yawOffset));
02218
02219
02220
02221
02222 tf::Matrix3x3 mat;
02223 mat.setRPY(0.0, 0.0, yawOffset);
02224 rpyAngles = mat * rpyAngles;
02225 poseTmp.getBasis().setRPY(rpyAngles.getX(), rpyAngles.getY(), rpyAngles.getZ());
02226
02227
02228
02229
02230
02231 targetFrameTrans.setIdentity();
02232 }
02233
02234
02235
02236 if(differential)
02237 {
02238 bool success = false;
02239
02240
02241
02242
02243 curMeasurement = poseTmp;
02244
02245
02246 if(previousMeasurements_.count(topicName) > 0 && previousMeasurementCovariances_.count(topicName) > 0)
02247 {
02248
02249
02250
02251
02252
02253
02254
02255 tf::Transform prevMeasurement = previousMeasurements_[topicName];
02256 poseTmp.setData(prevMeasurement.inverseTimes(poseTmp));
02257
02258 RF_DEBUG("Previous measurement:\n" << previousMeasurements_[topicName] <<
02259 "\nAfter removing previous measurement, measurement delta is:\n" << poseTmp << "\n");
02260
02261
02262
02263
02264 targetFrameTrans.setOrigin(tf::Vector3(0.0, 0.0, 0.0));
02265 poseTmp.mult(targetFrameTrans, poseTmp);
02266
02267 RF_DEBUG("After rotating to the target frame, measurement delta is:\n" << poseTmp << "\n");
02268
02269
02270
02271 double dt = msg->header.stamp.toSec() - lastMessageTimes_[topicName].toSec();
02272 double xVel = poseTmp.getOrigin().getX() / dt;
02273 double yVel = poseTmp.getOrigin().getY() / dt;
02274 double zVel = poseTmp.getOrigin().getZ() / dt;
02275
02276 double rollVel = 0;
02277 double pitchVel = 0;
02278 double yawVel = 0;
02279
02280 RosFilterUtilities::quatToRPY(poseTmp.getRotation(), rollVel, pitchVel, yawVel);
02281 rollVel /= dt;
02282 pitchVel /= dt;
02283 yawVel /= dt;
02284
02285 RF_DEBUG("Previous message time was " << lastMessageTimes_[topicName].toSec() <<
02286 ", current message time is " << msg->header.stamp.toSec() << ", delta is " <<
02287 dt << ", velocity is (vX, vY, vZ): (" << xVel << ", " << yVel << ", " << zVel <<
02288 ")\n" << "(vRoll, vPitch, vYaw): (" << rollVel << ", " << pitchVel << ", " <<
02289 yawVel << ")\n");
02290
02291
02292 geometry_msgs::TwistWithCovarianceStamped *twistPtr = new geometry_msgs::TwistWithCovarianceStamped();
02293 twistPtr->header = msg->header;
02294 twistPtr->header.frame_id = baseLinkFrameId_;
02295 twistPtr->twist.twist.linear.x = xVel;
02296 twistPtr->twist.twist.linear.y = yVel;
02297 twistPtr->twist.twist.linear.z = zVel;
02298 twistPtr->twist.twist.angular.x = rollVel;
02299 twistPtr->twist.twist.angular.y = pitchVel;
02300 twistPtr->twist.twist.angular.z = yawVel;
02301 std::vector<int> twistUpdateVec(STATE_SIZE, false);
02302 std::copy(updateVector.begin() + POSITION_OFFSET, updateVector.begin() + POSE_SIZE, twistUpdateVec.begin() + POSITION_V_OFFSET);
02303 std::copy(twistUpdateVec.begin(), twistUpdateVec.end(), updateVector.begin());
02304 geometry_msgs::TwistWithCovarianceStampedConstPtr ptr(twistPtr);
02305
02306
02307
02308
02309 Eigen::MatrixXd prevCovarRotated = rot6d * previousMeasurementCovariances_[topicName] * rot6d.transpose();
02310 covarianceRotated = (covarianceRotated.eval() + prevCovarRotated) * dt;
02311 copyCovariance(covarianceRotated, &(twistPtr->twist.covariance[0]), POSE_SIZE);
02312
02313 RF_DEBUG("Previous measurement covariance:\n" << previousMeasurementCovariances_[topicName] <<
02314 "\nPrevious measurement covariance rotated:\n" << prevCovarRotated <<
02315 "\nFinal twist covariance:\n" << covarianceRotated << "\n");
02316
02317
02318 success = prepareTwist(ptr, topicName + "_twist", twistPtr->header.frame_id, updateVector, measurement, measurementCovariance);
02319 }
02320
02321
02322 previousMeasurements_[topicName] = curMeasurement;
02323 previousMeasurementCovariances_[topicName] = covariance;
02324
02325 retVal = success;
02326 }
02327 else
02328 {
02329
02330 if(relative)
02331 {
02332 if(initialMeasurements_.count(topicName) == 0)
02333 {
02334 initialMeasurements_.insert(std::pair<std::string, tf::Transform>(topicName, poseTmp));
02335 }
02336
02337 tf::Transform initialMeasurement = initialMeasurements_[topicName];
02338 poseTmp.setData(initialMeasurement.inverseTimes(poseTmp));
02339 }
02340
02341
02342 poseTmp.mult(targetFrameTrans, poseTmp);
02343 poseTmp.frame_id_ = finalTargetFrame;
02344
02345
02346 measurement(StateMemberX) = poseTmp.getOrigin().x();
02347 measurement(StateMemberY) = poseTmp.getOrigin().y();
02348 measurement(StateMemberZ) = poseTmp.getOrigin().z();
02349
02350
02351 double roll, pitch, yaw;
02352 RosFilterUtilities::quatToRPY(poseTmp.getRotation(), roll, pitch, yaw);
02353 measurement(StateMemberRoll) = roll;
02354 measurement(StateMemberPitch) = pitch;
02355 measurement(StateMemberYaw) = yaw;
02356
02357 measurementCovariance.block(0, 0, POSE_SIZE, POSE_SIZE) = covarianceRotated.block(0, 0, POSE_SIZE, POSE_SIZE);
02358
02359
02360 if(twoDMode_)
02361 {
02362 forceTwoD(measurement, measurementCovariance, updateVector);
02363 }
02364
02365 retVal = true;
02366 }
02367 }
02368 else
02369 {
02370 retVal = false;
02371
02372 RF_DEBUG("Could not transform measurement into " << finalTargetFrame << ". Ignoring...");
02373 }
02374
02375 RF_DEBUG("\n----- /RosFilter::preparePose (" << topicName << ") ------\n");
02376
02377 return retVal;
02378 }
02379
02380 template<typename T>
02381 bool RosFilter<T>::prepareTwist(const geometry_msgs::TwistWithCovarianceStamped::ConstPtr &msg,
02382 const std::string &topicName,
02383 const std::string &targetFrame,
02384 std::vector<int> &updateVector,
02385 Eigen::VectorXd &measurement,
02386 Eigen::MatrixXd &measurementCovariance)
02387 {
02388 RF_DEBUG("------ RosFilter::prepareTwist (" << topicName << ") ------\n");
02389
02390
02391 tf::Vector3 twistLin(msg->twist.twist.linear.x,
02392 msg->twist.twist.linear.y,
02393 msg->twist.twist.linear.z);
02394 tf::Vector3 measTwistRot(msg->twist.twist.angular.x,
02395 msg->twist.twist.angular.y,
02396 msg->twist.twist.angular.z);
02397
02398
02399
02400
02401
02402 const Eigen::VectorXd &state = filter_.getState();
02403 tf::Vector3 stateTwistRot(state(StateMemberVroll),
02404 state(StateMemberVpitch),
02405 state(StateMemberVyaw));
02406
02407
02408 std::string msgFrame = (msg->header.frame_id == "" ? targetFrame : msg->header.frame_id);
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418 tf::Matrix3x3 maskLin(updateVector[StateMemberVx], 0, 0,
02419 0, updateVector[StateMemberVy], 0,
02420 0, 0, updateVector[StateMemberVz]);
02421
02422 tf::Matrix3x3 maskRot(updateVector[StateMemberVroll], 0, 0,
02423 0, updateVector[StateMemberVpitch], 0,
02424 0, 0, updateVector[StateMemberVyaw]);
02425
02426
02427 Eigen::MatrixXd covarianceRotated(TWIST_SIZE, TWIST_SIZE);
02428 covarianceRotated.setZero();
02429
02430 copyCovariance(&(msg->twist.covariance[0]), covarianceRotated, topicName, updateVector, POSITION_V_OFFSET, TWIST_SIZE);
02431
02432 RF_DEBUG("Original measurement as tf object:\nLinear: " << twistLin <<
02433 "Rotational: " << measTwistRot <<
02434 "\nOriginal update vector:\n" << updateVector <<
02435 "\nOriginal covariance matrix:\n" << covarianceRotated << "\n");
02436
02437
02438 tf::StampedTransform targetFrameTrans;
02439 bool canTransform = lookupTransformSafe(targetFrame, msgFrame, msg->header.stamp, targetFrameTrans);
02440
02441 if(canTransform)
02442 {
02443
02444
02445 measTwistRot = targetFrameTrans.getBasis() * measTwistRot;
02446 twistLin = targetFrameTrans.getBasis() * twistLin + targetFrameTrans.getOrigin().cross(stateTwistRot);
02447 maskLin = targetFrameTrans.getBasis() * maskLin;
02448 maskRot = targetFrameTrans.getBasis() * maskRot;
02449
02450
02451 updateVector[StateMemberVx] = static_cast<int>(maskLin.getRow(StateMemberVx - POSITION_V_OFFSET).length() >= 1e-6);
02452 updateVector[StateMemberVy] = static_cast<int>(maskLin.getRow(StateMemberVy - POSITION_V_OFFSET).length() >= 1e-6);
02453 updateVector[StateMemberVz] = static_cast<int>(maskLin.getRow(StateMemberVz - POSITION_V_OFFSET).length() >= 1e-6);
02454 updateVector[StateMemberVroll] = static_cast<int>(maskRot.getRow(StateMemberVroll - ORIENTATION_V_OFFSET).length() >= 1e-6);
02455 updateVector[StateMemberVpitch] = static_cast<int>(maskRot.getRow(StateMemberVpitch - ORIENTATION_V_OFFSET).length() >= 1e-6);
02456 updateVector[StateMemberVyaw] = static_cast<int>(maskRot.getRow(StateMemberVyaw - ORIENTATION_V_OFFSET).length() >= 1e-6);
02457
02458 RF_DEBUG(msg->header.frame_id << "->" << targetFrame << " transform:\n" << targetFrameTrans <<
02459 "\nAfter applying transform to " << targetFrame << ", update vector is:\n" << updateVector <<
02460 "\nAfter applying transform to " << targetFrame << ", measurement is:\n" <<
02461 "Linear: " << twistLin << "Rotational: " << measTwistRot << "\n");
02462
02463
02464
02465
02466
02467 tf::Matrix3x3 rot(targetFrameTrans.getRotation());
02468 Eigen::MatrixXd rot6d(TWIST_SIZE, TWIST_SIZE);
02469 rot6d.setIdentity();
02470
02471 for(size_t rInd = 0; rInd < POSITION_SIZE; ++rInd)
02472 {
02473 rot6d(rInd, 0) = rot.getRow(rInd).getX();
02474 rot6d(rInd, 1) = rot.getRow(rInd).getY();
02475 rot6d(rInd, 2) = rot.getRow(rInd).getZ();
02476 rot6d(rInd+POSITION_SIZE, 3) = rot.getRow(rInd).getX();
02477 rot6d(rInd+POSITION_SIZE, 4) = rot.getRow(rInd).getY();
02478 rot6d(rInd+POSITION_SIZE, 5) = rot.getRow(rInd).getZ();
02479 }
02480
02481
02482 covarianceRotated = rot6d * covarianceRotated.eval() * rot6d.transpose();
02483
02484 RF_DEBUG("Transformed covariance is \n" << covarianceRotated << "\n");
02485
02486
02487 measurement(StateMemberVx) = twistLin.getX();
02488 measurement(StateMemberVy) = twistLin.getY();
02489 measurement(StateMemberVz) = twistLin.getZ();
02490 measurement(StateMemberVroll) = measTwistRot.getX();
02491 measurement(StateMemberVpitch) = measTwistRot.getY();
02492 measurement(StateMemberVyaw) = measTwistRot.getZ();
02493
02494
02495 measurementCovariance.block(POSITION_V_OFFSET, POSITION_V_OFFSET, TWIST_SIZE, TWIST_SIZE) = covarianceRotated.block(0, 0, TWIST_SIZE, TWIST_SIZE);
02496
02497
02498 if(twoDMode_)
02499 {
02500 forceTwoD(measurement, measurementCovariance, updateVector);
02501 }
02502 }
02503 else
02504 {
02505 RF_DEBUG("Could not transform measurement into " << targetFrame << ". Ignoring...");
02506 }
02507
02508 RF_DEBUG("\n----- /RosFilter::prepareTwist (" << topicName << ") ------\n");
02509
02510 return canTransform;
02511 }
02512 }
02513
02514
02515
02516 template class RobotLocalization::RosFilter<RobotLocalization::Ekf>;
02517 template class RobotLocalization::RosFilter<RobotLocalization::Ukf>;
02518