Node::AddTrajectory --》LaunchSubscribers(options, trajectory_id);---》HandleOdometryMessage回调
/**
* @brief 处理里程计数据,里程计的数据走向有2个
* 第1个是传入PoseExtrapolator,用于位姿预测
* 第2个是传入SensorBridge,使用其传感器处理函数进行里程计数据处理
*
* @param[in] trajectory_id 轨迹id
* @param[in] sensor_id 里程计的topic名字
* @param[in] msg 里程计的ros格式的数据
*/
void Node::HandleOdometryMessage(const int trajectory_id,
const std::string& sensor_id,
const nav_msgs::Odometry::ConstPtr& msg) {
absl::MutexLock lock(&mutex_);
if (!sensor_samplers_.at(trajectory_id).odometry_sampler.Pulse()) {
return;
}
auto sensor_bridge_ptr = map_builder_bridge_.sensor_bridge(trajectory_id);
auto odometry_data_ptr = sensor_bridge_ptr->ToOdometryData(msg);
// extrapolators_使用里程计数据进行位姿预测
if (odometry_data_ptr != nullptr) {
extrapolators_.at(trajectory_id).AddOdometryData(*odometry_data_ptr);
}
sensor_bridge_ptr->HandleOdometryMessage(sensor_id, msg);
}
第1个是传入PoseExtrapolator,用于位姿预测
// 向odom数据队列中添加odom数据,并进行数据队列的修剪,并计算角速度与线速度
void PoseExtrapolator::AddOdometryData(
const sensor::OdometryData& odometry_data) {
CHECK(timed_pose_queue_.empty() ||
odometry_data.time >= timed_pose_queue_.back().time);
odometry_data_.push_back(odometry_data);
// 修剪odom的数据队列
TrimOdometryData();
// 数据队列中至少有2个数据
if (odometry_data_.size() < 2) {
return;
}
// TODO(whess): Improve by using more than just the last two odometry poses.
// Compute extrapolation in the tracking frame.
// 取最新与最老的两个里程计数据
const sensor::OdometryData& odometry_data_oldest = odometry_data_.front();
const sensor::OdometryData& odometry_data_newest = odometry_data_.back();
// 最新与最老odom数据间的时间差
const double odometry_time_delta =
common::ToSeconds(odometry_data_oldest.time - odometry_data_newest.time);
// 计算两个位姿间的坐标变换
const transform::Rigid3d odometry_pose_delta =
odometry_data_newest.pose.inverse() * odometry_data_oldest.pose;
// 两个位姿间的旋转量除以时间得到 tracking frame 的角速度
angular_velocity_from_odometry_ =
transform::RotationQuaternionToAngleAxisVector(
odometry_pose_delta.rotation()) /
odometry_time_delta;
if (timed_pose_queue_.empty()) {
return;
}
// 平移量除以时间得到 tracking frame 的线速度, 只在x方向有数值
const Eigen::Vector3d
linear_velocity_in_tracking_frame_at_newest_odometry_time =
odometry_pose_delta.translation() / odometry_time_delta;
// 根据位姿队列中最后一个位姿 乘以 上次添加位姿时的姿态预测到time时刻的姿态变化量
// 得到预测的 最新里程计数据时刻 tracking frame 在 local 坐标系下的姿态
const Eigen::Quaterniond orientation_at_newest_odometry_time =
timed_pose_queue_.back().pose.rotation() *
ExtrapolateRotation(odometry_data_newest.time,
odometry_imu_tracker_.get());
// 将tracking frame的线速度进行旋转, 得到 local 坐标系下 tracking frame 的线速度
linear_velocity_from_odometry_ =
orientation_at_newest_odometry_time *
linear_velocity_in_tracking_frame_at_newest_odometry_time;
}
第2个是传入SensorBridge,使用其传感器处理函数进行里程计数据处理
// 调用trajectory_builder_的AddSensorData进行数据的处理
void SensorBridge::HandleOdometryMessage(
const std::string& sensor_id, const nav_msgs::Odometry::ConstPtr& msg) {
// 数据类型与数据坐标系的转换
std::unique_ptr<carto::sensor::OdometryData> odometry_data =
ToOdometryData(msg);
if (odometry_data != nullptr) {
// tag: 这个trajectory_builder_是谁, 讲map_builder时候再揭晓
trajectory_builder_->AddSensorData(
sensor_id,
carto::sensor::OdometryData{odometry_data->time, odometry_data->pose});
}
}
trajectory_builder_->AddSensorData
// 里程计数据的处理, 数据走向有两个,一个是进入前端local_trajectory_builder_, 一个是进入后端pose_graph_
// 加入到后端之前, 先做一个距离的计算, 只有时间,移动距离,角度 变换量大于阈值才加入到后端中
void AddSensorData(const std::string& sensor_id,
const sensor::OdometryData& odometry_data) override {
CHECK(odometry_data.pose.IsValid()) << odometry_data.pose;
if (local_trajectory_builder_) {
local_trajectory_builder_->AddOdometryData(odometry_data);
}
// TODO(MichaelGrupp): Instead of having an optional filter on this level,
// odometry could be marginalized between nodes in the pose graph.
// Related issue: cartographer-project/cartographer/#1768
if (pose_graph_odometry_motion_filter_.has_value() &&
pose_graph_odometry_motion_filter_.value().IsSimilar(
odometry_data.time, odometry_data.pose)) {
return;
}
pose_graph_->AddOdometryData(trajectory_id_, odometry_data);
}
一个是进入前端local_trajectory_builder_->AddOdometryData(odometry_data);
// 将里程计数据加入到Extrapolator中
void LocalTrajectoryBuilder2D::AddOdometryData(
const sensor::OdometryData& odometry_data) {
if (extrapolator_ == nullptr) {
// Until we've initialized the extrapolator we cannot add odometry data.
LOG(INFO) << "Extrapolator not yet initialized.";
return;
}
extrapolator_->AddOdometryData(odometry_data);
}
一个是进入后端pose_graph_->AddOdometryData(trajectory_id_, odometry_data)
// 将 把里程计数据加入到优化问题中 这个任务放入到任务队列中
void PoseGraph2D::AddOdometryData(const int trajectory_id,
const sensor::OdometryData& odometry_data) {
AddWorkItem([=]() LOCKS_EXCLUDED(mutex_) {
absl::MutexLock locker(&mutex_);
if (CanAddWorkItemModifying(trajectory_id)) {
optimization_problem_->AddOdometryData(trajectory_id, odometry_data);
}
return WorkItem::Result::kDoNotRunOptimization;
});
}
optimization_problem_->AddOdometryData(trajectory_id, odometry_data);
// 添加里程计数据
void OptimizationProblem2D::AddOdometryData(
const int trajectory_id, const sensor::OdometryData& odometry_data) {
odometry_data_.Append(trajectory_id, odometry_data);
}