109 {
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
155 std::vector<double> timestamps_a;
157 &stds_a, ×tamps_a);
158 if (poses_a.empty()) {
159 return 0;
160 }
161
164 std::vector<double> timestamps_b;
166 &stds_b, ×tamps_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...
EigenVector< Eigen::Affine3d > EigenAffine3dVec
EigenVector< Eigen::Vector3d > EigenVector3dVec
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.