Apollo 11.0
自动驾驶开放平台
compare_poses.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#include <fstream>
18#include <iomanip>
19
20#include <boost/filesystem.hpp>
21#include <boost/program_options.hpp>
22
23#include "Eigen/Core"
24#include "Eigen/Geometry"
25#include "yaml-cpp/yaml.h"
26
27#include "cyber/common/log.h"
29
31
32using ::apollo::common::EigenAffine3dVec;
33using ::apollo::common::EigenVector3dVec;
34
35static bool LoadGnssAntennaExtrinsic(const std::string &file_path,
36 Eigen::Vector3d *imu_ant_offset) {
37 CHECK_NOTNULL(imu_ant_offset);
38
39 YAML::Node config = YAML::LoadFile(file_path);
40 if (config["leverarm"]) {
41 if (config["leverarm"]["primary"]["offset"]) {
42 (*imu_ant_offset)[0] =
43 config["leverarm"]["primary"]["offset"]["x"].as<double>();
44 (*imu_ant_offset)[1] =
45 config["leverarm"]["primary"]["offset"]["y"].as<double>();
46 (*imu_ant_offset)[2] =
47 config["leverarm"]["primary"]["offset"]["z"].as<double>();
48 }
49 return true;
50 }
51 return false;
52}
53
54static void PoseAndStdInterpolationByTime(
55 const EigenAffine3dVec &in_poses, const EigenVector3dVec &in_stds,
56 const std::vector<double> &in_timestamps,
57 const std::vector<double> &ref_timestamps,
58 std::map<unsigned int, Eigen::Affine3d> *out_poses,
59 std::map<unsigned int, Eigen::Vector3d> *out_stds) {
60 unsigned int index = 0;
61 for (size_t i = 0; i < ref_timestamps.size(); ++i) {
62 double ref_timestamp = ref_timestamps[i];
63 while (index < in_timestamps.size() &&
64 in_timestamps.at(index) < ref_timestamp) {
65 ++index;
66 }
67
68 if (index < in_timestamps.size()) {
69 if (index >= 1) {
70 double cur_timestamp = in_timestamps[index];
71 double pre_timestamp = in_timestamps[index - 1];
72 DCHECK_NE(cur_timestamp, pre_timestamp);
73
74 double t =
75 (cur_timestamp - ref_timestamp) / (cur_timestamp - pre_timestamp);
76 DCHECK_GE(t, 0.0);
77 DCHECK_LE(t, 1.0);
78
79 Eigen::Affine3d pre_pose = in_poses[index - 1];
80 Eigen::Affine3d cur_pose = in_poses[index];
81 Eigen::Quaterniond pre_quatd(pre_pose.linear());
82 Eigen::Translation3d pre_transd(pre_pose.translation());
83 Eigen::Quaterniond cur_quatd(cur_pose.linear());
84 Eigen::Translation3d cur_transd(cur_pose.translation());
85
86 Eigen::Quaterniond res_quatd = pre_quatd.slerp(1 - t, cur_quatd);
87
88 Eigen::Translation3d re_transd;
89 re_transd.x() = pre_transd.x() * t + cur_transd.x() * (1 - t);
90 re_transd.y() = pre_transd.y() * t + cur_transd.y() * (1 - t);
91 re_transd.z() = pre_transd.z() * t + cur_transd.z() * (1 - t);
92 (*out_poses)[static_cast<unsigned int>(i)] = re_transd * res_quatd;
93
94 Eigen::Vector3d pre_std = in_stds[index - 1];
95 Eigen::Vector3d cur_std = in_stds[index];
96 Eigen::Vector3d std;
97 std[0] = pre_std[0] * t + cur_std[0] * (1 - t);
98 std[1] = pre_std[1] * t + cur_std[1] * (1 - t);
99 std[2] = pre_std[2] * t + cur_std[2] * (1 - t);
100 (*out_stds)[static_cast<unsigned int>(i)] = std;
101 }
102 } else {
103 AERROR << "[ERROR] No more poses. Exit now.";
104 break;
105 }
106 }
107}
108
109int main(int argc, char **argv) {
110 boost::program_options::options_description boost_desc("Allowed options");
111 boost_desc.add_options()("help", "produce help message")(
112 "in_folder", boost::program_options::value<std::string>(),
113 "provide the output folder")("loc_file_a",
114 boost::program_options::value<std::string>(),
115 "provide gnss localization file.")(
116 "loc_file_b", boost::program_options::value<std::string>(),
117 "provide lidar localization file.")(
118 "compare_file", boost::program_options::value<std::string>(),
119 "provide compare file.")(
120 "imu_to_ant_offset_file",
121 boost::program_options::value<std::string>()->default_value(""),
122 "provide imu to ant offset file.");
123
124 boost::program_options::variables_map boost_args;
125 boost::program_options::store(
126 boost::program_options::parse_command_line(argc, argv, boost_desc),
127 boost_args);
128 boost::program_options::notify(boost_args);
129
130 if (boost_args.count("help") || !boost_args.count("in_folder")) {
131 AERROR << boost_desc << std::endl;
132 return 0;
133 }
134
135 const std::string in_folder = boost_args["in_folder"].as<std::string>();
136
137 const std::string loc_file_a =
138 in_folder + "/" + boost_args["loc_file_a"].as<std::string>();
139 const std::string loc_file_b =
140 in_folder + "/" + boost_args["loc_file_b"].as<std::string>();
141 const std::string compare_file =
142 in_folder + "/" + boost_args["compare_file"].as<std::string>();
143 const std::string imu_to_ant_offset_file =
144 boost_args["imu_to_ant_offset_file"].as<std::string>();
145
146 Eigen::Vector3d imu_ant_offset = Eigen::Vector3d::Zero();
147 if (imu_to_ant_offset_file != "") {
148 if (!LoadGnssAntennaExtrinsic(imu_to_ant_offset_file, &imu_ant_offset)) {
149 return 0;
150 }
151 }
152
153 EigenAffine3dVec poses_a;
154 EigenVector3dVec stds_a;
155 std::vector<double> timestamps_a;
157 &stds_a, &timestamps_a);
158 if (poses_a.empty()) {
159 return 0;
160 }
161
162 EigenAffine3dVec poses_b;
163 EigenVector3dVec stds_b;
164 std::vector<double> timestamps_b;
166 &stds_b, &timestamps_b);
167 if (poses_b.empty()) {
168 return 0;
169 }
170
171 std::map<unsigned int, Eigen::Affine3d> out_poses_a;
172 std::map<unsigned int, Eigen::Vector3d> out_stds_a;
173 std::map<unsigned int, Eigen::Affine3d> out_poses_b;
174 std::map<unsigned int, Eigen::Vector3d> out_stds_b;
175
176 PoseAndStdInterpolationByTime(poses_b, stds_b, timestamps_b, timestamps_a,
177 &out_poses_b, &out_stds_b);
178
179 PoseAndStdInterpolationByTime(poses_a, stds_a, timestamps_a, timestamps_a,
180 &out_poses_a, &out_stds_a);
181
182 if (out_poses_a.empty() || out_poses_b.empty()) {
183 return 0;
184 }
185
186 std::vector<unsigned int> vec_idx;
187 std::vector<double> vec_timestamp;
188 std::vector<double> vec_x_diff;
189 std::vector<double> vec_y_diff;
190 std::vector<double> vec_z_diff;
191 std::vector<double> vec_roll_diff;
192 std::vector<double> vec_pitch_diff;
193 std::vector<double> vec_yaw_diff;
194
195 for (unsigned int idx = 0; idx < timestamps_a.size(); idx++) {
196 auto pose_a_found_iter = out_poses_a.find(idx);
197 if (pose_a_found_iter != out_poses_a.end()) {
198 AINFO << "Find pose a.";
199 const Eigen::Affine3d &pose_a = pose_a_found_iter->second;
200
201 Eigen::Quaterniond quatd_a(pose_a.linear());
202 Eigen::Translation3d transd_a(pose_a.translation());
204 quatd_a.w(), quatd_a.x(), quatd_a.y(), quatd_a.z());
205 double roll_a = euler_a.roll();
206 double pitch_a = euler_a.pitch();
207 double yaw_a = euler_a.yaw();
208
209 auto pose_b_found_iter = out_poses_b.find(idx);
210 if (pose_b_found_iter != out_poses_b.end()) {
211 AINFO << "Find pose b.";
212 const Eigen::Affine3d &pose_b = pose_b_found_iter->second;
213 Eigen::Quaterniond quatd_b(pose_b.linear());
214 Eigen::Translation3d transd_b(pose_b.translation());
216 quatd_b.w(), quatd_b.x(), quatd_b.y(), quatd_b.z());
217 double roll_b = euler_b.roll();
218 double pitch_b = euler_b.pitch();
219 double yaw_b = euler_b.yaw();
220
221 Eigen::Vector3d offset = quatd_b * imu_ant_offset;
222 transd_a.x() = transd_a.x() - offset[0];
223 transd_a.y() = transd_a.y() - offset[1];
224 transd_a.z() = transd_a.z() - offset[2];
225
226 double x_diff = fabs(transd_a.x() - transd_b.x());
227 double y_diff = fabs(transd_a.y() - transd_b.y());
228 double z_diff = fabs(transd_a.z() - transd_b.z());
229 double roll_diff = fabs(roll_a - roll_b) * 180.0 / M_PI;
230 double pitch_diff = fabs(pitch_a - pitch_b) * 180.0 / M_PI;
231 double yaw_diff = fabs(yaw_a - yaw_b);
232 yaw_diff = std::min(yaw_diff, 2.0 * M_PI - yaw_diff) * 180.0 / M_PI;
233
234 vec_idx.push_back(idx);
235 vec_timestamp.push_back(timestamps_a[idx]);
236 vec_x_diff.push_back(x_diff);
237 vec_y_diff.push_back(y_diff);
238 vec_z_diff.push_back(z_diff);
239 vec_roll_diff.push_back(roll_diff);
240 vec_pitch_diff.push_back(pitch_diff);
241 vec_yaw_diff.push_back(yaw_diff);
242 }
243 }
244 }
245
246 if (vec_idx.empty()) {
247 return 0;
248 }
249
250 std::ofstream file(compare_file.c_str());
251 for (unsigned int i = 0; i < vec_idx.size(); ++i) {
252 file << vec_idx[i] << " " << std::setprecision(13) << vec_timestamp[i]
253 << " " << vec_x_diff[i] << " " << vec_y_diff[i] << " " << vec_z_diff[i]
254 << " " << vec_roll_diff[i] << " " << vec_pitch_diff[i] << " "
255 << vec_yaw_diff[i] << std::endl;
256 }
257 file.close();
258}
Any orientation of a rigid body on a 3-D space can be achieved by composing three rotations about the...
int main(int argc, char **argv)
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
void LoadPosesAndStds(const std::string &file_path, ::apollo::common::EigenAffine3dVec *poses, ::apollo::common::EigenVector3dVec *stds, std::vector< double > *timestamps)
Load poses and stds their timestamps.
Definition future.h:29
Contains a number of helper functions related to quaternions.
The utilities of velodyne.