cost_helpers_impl.h
Go to the documentation of this file.
00001 /*
00002  * Copyright 2018 The Cartographer Authors
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *      http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef CARTOGRAPHER_MAPPING_INTERNAL_OPTIMIZATION_COST_FUNCTIONS_COST_HELPERS_IMPL_H_
00018 #define CARTOGRAPHER_MAPPING_INTERNAL_OPTIMIZATION_COST_FUNCTIONS_COST_HELPERS_IMPL_H_
00019 
00020 #include "Eigen/Core"
00021 #include "cartographer/transform/rigid_transform.h"
00022 #include "cartographer/transform/transform.h"
00023 
00024 namespace cartographer {
00025 namespace mapping {
00026 namespace optimization {
00027 
00028 template <typename T>
00029 static std::array<T, 3> ComputeUnscaledError(
00030     const transform::Rigid2d& relative_pose, const T* const start,
00031     const T* const end) {
00032   const T cos_theta_i = cos(start[2]);
00033   const T sin_theta_i = sin(start[2]);
00034   const T delta_x = end[0] - start[0];
00035   const T delta_y = end[1] - start[1];
00036   const T h[3] = {cos_theta_i * delta_x + sin_theta_i * delta_y,
00037                   -sin_theta_i * delta_x + cos_theta_i * delta_y,
00038                   end[2] - start[2]};
00039   return {{T(relative_pose.translation().x()) - h[0],
00040            T(relative_pose.translation().y()) - h[1],
00041            common::NormalizeAngleDifference(
00042                T(relative_pose.rotation().angle()) - h[2])}};
00043 }
00044 
00045 template <typename T>
00046 std::array<T, 3> ScaleError(const std::array<T, 3>& error,
00047                             double translation_weight, double rotation_weight) {
00048   // clang-format off
00049   return {{
00050       error[0] * translation_weight,
00051       error[1] * translation_weight,
00052       error[2] * rotation_weight
00053   }};
00054   // clang-format on
00055 }
00056 
00057 template <typename T>
00058 static std::array<T, 6> ComputeUnscaledError(
00059     const transform::Rigid3d& relative_pose, const T* const start_rotation,
00060     const T* const start_translation, const T* const end_rotation,
00061     const T* const end_translation) {
00062   const Eigen::Quaternion<T> R_i_inverse(start_rotation[0], -start_rotation[1],
00063                                          -start_rotation[2],
00064                                          -start_rotation[3]);
00065 
00066   const Eigen::Matrix<T, 3, 1> delta(end_translation[0] - start_translation[0],
00067                                      end_translation[1] - start_translation[1],
00068                                      end_translation[2] - start_translation[2]);
00069   const Eigen::Matrix<T, 3, 1> h_translation = R_i_inverse * delta;
00070 
00071   const Eigen::Quaternion<T> h_rotation_inverse =
00072       Eigen::Quaternion<T>(end_rotation[0], -end_rotation[1], -end_rotation[2],
00073                            -end_rotation[3]) *
00074       Eigen::Quaternion<T>(start_rotation[0], start_rotation[1],
00075                            start_rotation[2], start_rotation[3]);
00076 
00077   const Eigen::Matrix<T, 3, 1> angle_axis_difference =
00078       transform::RotationQuaternionToAngleAxisVector(
00079           h_rotation_inverse * relative_pose.rotation().cast<T>());
00080 
00081   return {{T(relative_pose.translation().x()) - h_translation[0],
00082            T(relative_pose.translation().y()) - h_translation[1],
00083            T(relative_pose.translation().z()) - h_translation[2],
00084            angle_axis_difference[0], angle_axis_difference[1],
00085            angle_axis_difference[2]}};
00086 }
00087 
00088 template <typename T>
00089 std::array<T, 6> ScaleError(const std::array<T, 6>& error,
00090                             double translation_weight, double rotation_weight) {
00091   // clang-format off
00092   return {{
00093       error[0] * translation_weight,
00094       error[1] * translation_weight,
00095       error[2] * translation_weight,
00096       error[3] * rotation_weight,
00097       error[4] * rotation_weight,
00098       error[5] * rotation_weight
00099   }};
00100   // clang-format on
00101 }
00102 
00103 //  Eigen implementation of slerp is not compatible with Ceres on all supported
00104 //  platforms. Our own implementation is used instead.
00105 template <typename T>
00106 std::array<T, 4> SlerpQuaternions(const T* const start, const T* const end,
00107                                   double factor) {
00108   // Angle 'theta' is the half-angle "between" quaternions. It can be computed
00109   // as the arccosine of their dot product.
00110   const T cos_theta = start[0] * end[0] + start[1] * end[1] +
00111                       start[2] * end[2] + start[3] * end[3];
00112   // Avoid using ::abs which would cast to integer.
00113   const T abs_cos_theta = ceres::abs(cos_theta);
00114   // If numerical error brings 'cos_theta' outside [-1 + epsilon, 1 - epsilon]
00115   // interval, then the quaternions are likely to be collinear.
00116   T prev_scale(1. - factor);
00117   T next_scale(factor);
00118   if (abs_cos_theta < T(1. - 1e-5)) {
00119     const T theta = acos(abs_cos_theta);
00120     const T sin_theta = sin(theta);
00121     prev_scale = sin((1. - factor) * theta) / sin_theta;
00122     next_scale = sin(factor * theta) / sin_theta;
00123   }
00124   if (cos_theta < T(0.)) {
00125     next_scale = -next_scale;
00126   }
00127   return {{prev_scale * start[0] + next_scale * end[0],
00128            prev_scale * start[1] + next_scale * end[1],
00129            prev_scale * start[2] + next_scale * end[2],
00130            prev_scale * start[3] + next_scale * end[3]}};
00131 }
00132 
00133 template <typename T>
00134 std::tuple<std::array<T, 4> /* rotation */, std::array<T, 3> /* translation */>
00135 InterpolateNodes3D(const T* const prev_node_rotation,
00136                    const T* const prev_node_translation,
00137                    const T* const next_node_rotation,
00138                    const T* const next_node_translation,
00139                    const double interpolation_parameter) {
00140   return std::make_tuple(
00141       SlerpQuaternions(prev_node_rotation, next_node_rotation,
00142                        interpolation_parameter),
00143       std::array<T, 3>{
00144           {prev_node_translation[0] +
00145                interpolation_parameter *
00146                    (next_node_translation[0] - prev_node_translation[0]),
00147            prev_node_translation[1] +
00148                interpolation_parameter *
00149                    (next_node_translation[1] - prev_node_translation[1]),
00150            prev_node_translation[2] +
00151                interpolation_parameter *
00152                    (next_node_translation[2] - prev_node_translation[2])}});
00153 }
00154 
00155 template <typename T>
00156 std::tuple<std::array<T, 4> /* rotation */, std::array<T, 3> /* translation */>
00157 InterpolateNodes2D(const T* const prev_node_pose,
00158                    const Eigen::Quaterniond& prev_node_gravity_alignment,
00159                    const T* const next_node_pose,
00160                    const Eigen::Quaterniond& next_node_gravity_alignment,
00161                    const double interpolation_parameter) {
00162   // The following is equivalent to (Embed3D(prev_node_pose) *
00163   // Rigid3d::Rotation(prev_node_gravity_alignment)).rotation().
00164   const Eigen::Quaternion<T> prev_quaternion(
00165       (Eigen::AngleAxis<T>(prev_node_pose[2], Eigen::Matrix<T, 3, 1>::UnitZ()) *
00166        prev_node_gravity_alignment.cast<T>())
00167           .normalized());
00168   const std::array<T, 4> prev_node_rotation = {
00169       {prev_quaternion.w(), prev_quaternion.x(), prev_quaternion.y(),
00170        prev_quaternion.z()}};
00171 
00172   // The following is equivalent to (Embed3D(next_node_pose) *
00173   // Rigid3d::Rotation(next_node_gravity_alignment)).rotation().
00174   const Eigen::Quaternion<T> next_quaternion(
00175       (Eigen::AngleAxis<T>(next_node_pose[2], Eigen::Matrix<T, 3, 1>::UnitZ()) *
00176        next_node_gravity_alignment.cast<T>())
00177           .normalized());
00178   const std::array<T, 4> next_node_rotation = {
00179       {next_quaternion.w(), next_quaternion.x(), next_quaternion.y(),
00180        next_quaternion.z()}};
00181 
00182   return std::make_tuple(
00183       SlerpQuaternions(prev_node_rotation.data(), next_node_rotation.data(),
00184                        interpolation_parameter),
00185       std::array<T, 3>{
00186           {prev_node_pose[0] + interpolation_parameter *
00187                                    (next_node_pose[0] - prev_node_pose[0]),
00188            prev_node_pose[1] + interpolation_parameter *
00189                                    (next_node_pose[1] - prev_node_pose[1]),
00190            T(0)}});
00191 }
00192 
00193 }  // namespace optimization
00194 }  // namespace mapping
00195 }  // namespace cartographer
00196 
00197 #endif  // CARTOGRAPHER_MAPPING_INTERNAL_OPTIMIZATION_COST_FUNCTIONS_COST_HELPERS_IMPL_H_


cartographer
Author(s): The Cartographer Authors
autogenerated on Thu May 9 2019 02:27:35