├── aurova_odom ├── CMakeLists.txt └── package.xml ├── .project ├── dualquat_LOAM ├── include │ ├── dualquat │ │ ├── dualquat.h │ │ ├── quat_exponential.h │ │ ├── dualquat_query.h │ │ ├── quat_relational.h │ │ ├── dualquat_relational.h │ │ ├── relational.h │ │ ├── dualquat_exponential.h │ │ ├── dualquat_common.h │ │ ├── dualquat_helper.h │ │ ├── dualquat_transformation.h │ │ └── dualquat_base.h │ ├── KDTree_STD.h │ ├── laserMappingClass.h │ └── odomEstimationClass.h ├── src │ ├── KDTree_STD.cpp │ ├── laserMappingNode.cpp │ └── laserMappingClass.cpp ├── config │ ├── config_NTU.yaml │ ├── config_Blue.yaml │ ├── config_Heli.yaml │ ├── config_conSLAM.yaml │ ├── config_Kitti.yaml │ └── config_hesai_pandar.yaml ├── package.xml ├── launch │ ├── odomEstimation_HeLiPR_display_STD.launch │ ├── odomEstimation_HeLiPR_dataset.launch │ ├── odomEstimation_hensai.launch │ ├── odomEstimation_KITTI_dataset.launch │ ├── odomEstimation_NTU_dataset.launch │ ├── odomEstimation_KITTI_display_STD.launch │ ├── odomEstimation_conSLAM_dataset.launch │ ├── odomEstimation_ouster_BLUE_dataset.launch │ └── odomEstimation_ouster_BLUE_display_std.launch ├── CMakeLists.txt ├── Dockerfile ├── README.md └── rviz │ ├── kitti_fov.rviz │ ├── kitti_displayed_std.rviz │ └── heliPR_displayed_std.rviz ├── ackermann_to_odom ├── launch │ └── start_odometry.launch ├── cfg │ └── AckermannToOdom.cfg ├── package.xml ├── CMakeLists.txt ├── src │ ├── ackermann_to_odom_alg_node.cpp │ └── ackermann_to_odom_alg.cpp └── include │ ├── ackermann_to_odom_alg.h │ └── ackermann_to_odom_alg_node.h ├── gps_to_odom ├── src │ └── gps_to_odom_alg.cpp ├── cfg │ └── GpsToOdom.cfg ├── package.xml ├── CMakeLists.txt └── include │ ├── gps_to_odom_alg.h │ └── gps_to_odom_alg_node.h ├── odom_estimation_pc ├── src │ ├── lidar.cpp │ ├── lidarOptimization.cpp │ └── odomEstimationNode.cpp ├── include │ ├── lidar.h │ ├── lidarOptimization.h │ └── odomEstimationClass.h ├── package.xml ├── launch │ ├── odomEstimation_ouster.launch │ ├── odomEstimation_ouster_lite.launch │ ├── odomEstimation_carla.launch │ ├── odomEstimation_VLP16.launch │ └── odomEstimation_KITTI_dataset.launch ├── CMakeLists.txt └── rviz │ └── odomEstimation.rviz └── README.md /aurova_odom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(aurova_odom) 3 | find_package(catkin REQUIRED) 4 | catkin_metapackage() 5 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | aurova_odom 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat.h 3 | */ 4 | #pragma once 5 | 6 | #include "dualquat_base.h" 7 | #include "dualquat_relational.h" 8 | #include "dualquat_query.h" 9 | #include "dualquat_common.h" 10 | #include "dualquat_exponential.h" 11 | #include "dualquat_transformation.h" 12 | #include "dualquat_helper.h" 13 | -------------------------------------------------------------------------------- /ackermann_to_odom/launch/start_odometry.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /dualquat_LOAM/src/KDTree_STD.cpp: -------------------------------------------------------------------------------- 1 | #include "include/KDTree_STD.h" 2 | 3 | STDesc findClosestDescriptor(const STDesc& query, STDescKDTree& index, STDescCloud& cloud) { 4 | 5 | std::vector queryVec = query.toVector(); 6 | 7 | size_t ret_index; 8 | double out_dist_sqr; 9 | nanoflann::KNNResultSet resultSet(1); 10 | resultSet.init(&ret_index, &out_dist_sqr); 11 | 12 | index.findNeighbors(resultSet, queryVec.data(), nanoflann::SearchParameters(10)); 13 | 14 | return cloud.descriptors[ret_index]; 15 | } 16 | -------------------------------------------------------------------------------- /gps_to_odom/src/gps_to_odom_alg.cpp: -------------------------------------------------------------------------------- 1 | #include "gps_to_odom_alg.h" 2 | 3 | GpsToOdomAlgorithm::GpsToOdomAlgorithm(void) 4 | { 5 | pthread_mutex_init(&this->access_,NULL); 6 | } 7 | 8 | GpsToOdomAlgorithm::~GpsToOdomAlgorithm(void) 9 | { 10 | pthread_mutex_destroy(&this->access_); 11 | } 12 | 13 | void GpsToOdomAlgorithm::config_update(Config& config, uint32_t level) 14 | { 15 | this->lock(); 16 | 17 | // save the current configuration 18 | this->config_=config; 19 | 20 | this->unlock(); 21 | } 22 | 23 | // GpsToOdomAlgorithm Public API 24 | -------------------------------------------------------------------------------- /dualquat_LOAM/config/config_NTU.yaml: -------------------------------------------------------------------------------- 1 | # pre process 2 | ds_size: 0.2 3 | maximum_corner_num: 10 4 | 5 | # key points 6 | plane_detection_thre: 0.01 7 | plane_merge_normal_thre: 0.2 8 | voxel_size: 2.0 9 | voxel_init_num: 5 10 | proj_image_resolution: 0.5 11 | proj_dis_min: 0 12 | proj_dis_max: 5 13 | corner_thre: 5 14 | 15 | # std descriptor 16 | descriptor_near_num: 5 17 | descriptor_min_len: 1 18 | descriptor_max_len: 500 19 | non_max_suppression_radius: 3.0 20 | std_side_resolution: 0.1 21 | 22 | # candidate search 23 | skip_near_num: 2 24 | candidate_num: 2 25 | sub_frame_num: 1 26 | vertex_diff_threshold: 0.5 27 | rough_dis_threshold: 0.01 28 | normal_threshold: 0.2 29 | dis_threshold: 0.1 30 | icp_threshold: 0.4 31 | 32 | # window size 33 | max_window_size: 10.0 34 | # for Kitti max_window_size: 10.0 35 | # for BLUE max_window_size: 2.0 36 | kdtree_threshold: 10.0 37 | epsilon: 0.001 -------------------------------------------------------------------------------- /dualquat_LOAM/config/config_Blue.yaml: -------------------------------------------------------------------------------- 1 | # pre process 2 | ds_size: 0.5 3 | maximum_corner_num: 10 4 | 5 | # key points 6 | plane_detection_thre: 0.01 7 | plane_merge_normal_thre: 0.2 8 | voxel_size: 2.0 9 | voxel_init_num: 10 10 | proj_image_resolution: 0.5 11 | proj_dis_min: 0 12 | proj_dis_max: 5 13 | corner_thre: 10 14 | 15 | # std descriptor 16 | descriptor_near_num: 10 17 | descriptor_min_len: 1 18 | descriptor_max_len: 500 19 | non_max_suppression_radius: 3.0 20 | std_side_resolution: 0.5 21 | 22 | # candidate search 23 | skip_near_num: 5 24 | candidate_num: 5 25 | sub_frame_num: 1 26 | vertex_diff_threshold: 0.5 27 | rough_dis_threshold: 0.01 28 | normal_threshold: 0.2 29 | dis_threshold: 0.5 30 | icp_threshold: 0.4 31 | 32 | # window size 33 | max_window_size: 10.0 34 | # for Kitti max_window_size: 10.0 35 | # for BLUE max_window_size: 2.0 36 | kdtree_threshold: 10.0 37 | epsilon: 0.001 -------------------------------------------------------------------------------- /dualquat_LOAM/config/config_Heli.yaml: -------------------------------------------------------------------------------- 1 | # pre process 2 | ds_size: 0.2 3 | maximum_corner_num: 10 4 | 5 | # key points 6 | plane_detection_thre: 0.01 7 | plane_merge_normal_thre: 0.2 8 | voxel_size: 2.0 9 | voxel_init_num: 10 10 | proj_image_resolution: 0.5 11 | proj_dis_min: 0 12 | proj_dis_max: 5 13 | corner_thre: 10 14 | 15 | # std descriptor 16 | descriptor_near_num: 10 17 | descriptor_min_len: 1 18 | descriptor_max_len: 500 19 | non_max_suppression_radius: 3.0 20 | std_side_resolution: 0.5 21 | 22 | # candidate search 23 | skip_near_num: 5 24 | candidate_num: 5 25 | sub_frame_num: 1 26 | vertex_diff_threshold: 0.5 27 | rough_dis_threshold: 0.01 28 | normal_threshold: 0.2 29 | dis_threshold: 0.5 30 | icp_threshold: 0.4 31 | 32 | # window size 33 | max_window_size: 10.0 34 | # for Kitti max_window_size: 10.0 35 | # for BLUE max_window_size: 2.0 36 | kdtree_threshold: 10.0 37 | epsilon: 0.2 -------------------------------------------------------------------------------- /dualquat_LOAM/config/config_conSLAM.yaml: -------------------------------------------------------------------------------- 1 | # pre process 2 | ds_size: 0.1 3 | maximum_corner_num: 10 4 | 5 | # key points 6 | plane_detection_thre: 0.01 7 | plane_merge_normal_thre: 0.2 8 | voxel_size: 2.0 9 | voxel_init_num: 5 10 | proj_image_resolution: 0.5 11 | proj_dis_min: 0 12 | proj_dis_max: 5 13 | corner_thre: 5 14 | 15 | # std descriptor 16 | descriptor_near_num: 5 17 | descriptor_min_len: 1 18 | descriptor_max_len: 500 19 | non_max_suppression_radius: 3.0 20 | std_side_resolution: 0.1 21 | 22 | # candidate search 23 | skip_near_num: 2 24 | candidate_num: 2 25 | sub_frame_num: 1 26 | vertex_diff_threshold: 0.5 27 | rough_dis_threshold: 0.01 28 | normal_threshold: 0.2 29 | dis_threshold: 0.1 30 | icp_threshold: 0.4 31 | 32 | # window size 33 | max_window_size: 10.0 34 | # for Kitti max_window_size: 10.0 35 | # for BLUE max_window_size: 2.0 36 | kdtree_threshold: 10.0 37 | epsilon: 0.001 -------------------------------------------------------------------------------- /dualquat_LOAM/config/config_Kitti.yaml: -------------------------------------------------------------------------------- 1 | # pre process 2 | ds_size: 0.2 3 | maximum_corner_num: 10 4 | 5 | # key points 6 | plane_detection_thre: 0.01 7 | plane_merge_normal_thre: 0.2 8 | voxel_size: 2.0 9 | voxel_init_num: 10 10 | proj_image_resolution: 0.5 11 | proj_dis_min: 0 12 | proj_dis_max: 5 13 | corner_thre: 10 14 | 15 | # std descriptor 16 | descriptor_near_num: 10 17 | descriptor_min_len: 1 18 | descriptor_max_len: 500 19 | non_max_suppression_radius: 3.0 20 | std_side_resolution: 0.5 21 | 22 | # candidate search 23 | skip_near_num: 5 24 | candidate_num: 5 25 | sub_frame_num: 1 26 | vertex_diff_threshold: 0.5 27 | rough_dis_threshold: 0.01 28 | normal_threshold: 0.2 29 | dis_threshold: 0.5 30 | icp_threshold: 0.4 31 | 32 | # window size 33 | max_window_size: 10.0 34 | # for Kitti max_window_size: 10.0 35 | # for BLUE max_window_size: 2.0 36 | kdtree_threshold: 10.0 37 | epsilon: 0.001 38 | -------------------------------------------------------------------------------- /dualquat_LOAM/config/config_hesai_pandar.yaml: -------------------------------------------------------------------------------- 1 | # pre process 2 | ds_size: 0.1 3 | maximum_corner_num: 20 4 | 5 | # key points 6 | plane_detection_thre: 0.01 7 | plane_merge_normal_thre: 0.2 8 | voxel_size: 2.0 9 | voxel_init_num: 10 10 | proj_image_resolution: 0.5 11 | proj_dis_min: 0 12 | proj_dis_max: 5 13 | corner_thre: 10 14 | 15 | # std descriptor 16 | descriptor_near_num: 5 17 | descriptor_min_len: 1 18 | descriptor_max_len: 5000 19 | non_max_suppression_radius: 1.0 20 | std_side_resolution: 0.2 21 | 22 | # candidate search 23 | skip_near_num: 5 24 | candidate_num: 5 25 | sub_frame_num: 1 26 | vertex_diff_threshold: 0.5 27 | rough_dis_threshold: 0.01 28 | normal_threshold: 0.2 29 | dis_threshold: 0.5 30 | icp_threshold: 0.4 31 | 32 | # window size 33 | max_window_size: 10.0 34 | # for Kitti max_window_size: 10.0 35 | # for BLUE max_window_size: 2.0 36 | kdtree_threshold: 10.0 37 | epsilon: 0.001 -------------------------------------------------------------------------------- /dualquat_LOAM/include/KDTree_STD.h: -------------------------------------------------------------------------------- 1 | #ifndef KDTREEDESC_H 2 | #define KDTREEDESC_H 3 | 4 | #include 5 | #include 6 | #include "STDesc.h" 7 | 8 | struct STDescCloud { 9 | std::vector descriptors; 10 | 11 | inline size_t kdtree_get_point_count() const { return descriptors.size(); } 12 | 13 | inline double kdtree_get_pt(const size_t idx, const size_t dim) const { 14 | return descriptors[idx].toVector()[dim]; 15 | } 16 | 17 | template 18 | bool kdtree_get_bbox(BBOX&) const { return false; } 19 | 20 | }; 21 | 22 | typedef nanoflann::KDTreeSingleIndexAdaptor< 23 | nanoflann::L2_Simple_Adaptor, 24 | STDescCloud, 25 | 18 /* Dimensiones (3 side_length + 3 angle + 3 center + 3*3 vertices) */ 26 | > STDescKDTree; 27 | 28 | STDesc findClosestDescriptor(const STDesc& query, STDescKDTree& index, STDescCloud& cloud); 29 | 30 | #endif // KDTREEDESC_H 31 | -------------------------------------------------------------------------------- /odom_estimation_pc/src/lidar.cpp: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | // Author of Lilo: Edison Velasco 6 | // Email evs25@alu.ua.es 7 | 8 | #include "lidar.h" 9 | 10 | 11 | lidar::Lidar::Lidar(){ 12 | 13 | } 14 | 15 | 16 | void lidar::Lidar::setLines(double num_lines_in){ 17 | num_lines=num_lines_in; 18 | } 19 | 20 | void lidar::Lidar::setValidationAngle(bool validation_height_in){ 21 | validation_height = validation_height_in; 22 | } 23 | 24 | void lidar::Lidar::setVerticalAngle(double velodyne_height_in){ 25 | velodyne_height = velodyne_height_in; 26 | } 27 | 28 | 29 | void lidar::Lidar::setVerticalResolution(double vertical_angle_resolution_in){ 30 | vertical_angle_resolution = vertical_angle_resolution_in; 31 | } 32 | 33 | 34 | void lidar::Lidar::setScanPeriod(double scan_period_in){ 35 | scan_period = scan_period_in; 36 | } 37 | 38 | 39 | void lidar::Lidar::setMaxDistance(double max_distance_in){ 40 | max_distance = max_distance_in; 41 | } 42 | 43 | void lidar::Lidar::setMinDistance(double min_distance_in){ 44 | min_distance = min_distance_in; 45 | } 46 | -------------------------------------------------------------------------------- /odom_estimation_pc/include/lidar.h: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | // Author of Lilo: Edison Velasco 6 | // Email evs25@alu.ua.es 7 | 8 | #ifndef _LIDAR_H_ 9 | #define _LIDAR_H_ 10 | 11 | //define lidar parameter 12 | 13 | namespace lidar{ 14 | 15 | class Lidar 16 | { 17 | public: 18 | Lidar(); 19 | 20 | void setScanPeriod(double scan_period_in); 21 | void setLines(double num_lines_in); 22 | void setVerticalAngle(double velodyne_height_in); 23 | void setValidationAngle(bool validation_height_in); 24 | void setVerticalResolution(double vertical_angle_resolution_in); 25 | void setMaxDistance(double max_distance_in); 26 | void setMinDistance(double min_distance_in); 27 | 28 | double max_distance; 29 | double min_distance; 30 | int num_lines; 31 | double scan_period; 32 | int points_per_line; 33 | double horizontal_angle_resolution; 34 | double horizontal_angle; 35 | double vertical_angle_resolution; 36 | double velodyne_height; 37 | bool validation_height; 38 | }; 39 | 40 | 41 | } 42 | 43 | 44 | #endif // _LIDAR_H_ 45 | 46 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/quat_exponential.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/quat_exponential.h 3 | * @brief This file provides exponential functions for quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace dualquat 10 | { 11 | 12 | /** 13 | * Returns a exponential of a quaternion. 14 | */ 15 | template 16 | Quaternion 17 | exp(const Quaternion& q) 18 | { 19 | const auto vn = q.vec().norm(); 20 | const auto sinc = (vn > T(0)) ? std::sin(vn) / vn : T(1); 21 | 22 | Quaternion temp; 23 | temp.w() = std::cos(vn); 24 | temp.vec() = sinc * q.vec(); 25 | temp.coeffs() *= std::exp(q.w()); 26 | return temp; 27 | } 28 | 29 | /** 30 | * Returns a logarithm of a quaternion. 31 | */ 32 | template 33 | Quaternion 34 | log(const Quaternion& q) 35 | { 36 | const auto vn = q.vec().norm(); 37 | const auto phi = std::atan2(vn, q.w()); 38 | const auto qn = q.norm(); 39 | const auto phi_over_vn = (vn > T(0)) ? phi / vn : T(1) / qn; 40 | 41 | Quaternion temp; 42 | temp.w() = std::log(qn); 43 | temp.vec() = phi_over_vn * q.vec(); 44 | return temp; 45 | } 46 | 47 | } // namespace dualquat 48 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_query.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_query.h 3 | * @brief This file provides query functions for dual quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include "dualquat_relational.h" 8 | 9 | namespace dualquat 10 | { 11 | 12 | template 13 | bool 14 | is_zero(const DualQuaternion& dq, T tol) 15 | { 16 | return almost_zero(dq, tol); 17 | } 18 | 19 | template 20 | bool 21 | is_real(const DualQuaternion& dq, T tol) 22 | { 23 | return almost_zero(dq.real().vec(), tol) 24 | && almost_zero(dq.dual().vec(), tol); 25 | } 26 | 27 | template 28 | bool 29 | is_pure(const DualQuaternion& dq, T tol) 30 | { 31 | using Matrix1 = Eigen::Matrix; 32 | 33 | return almost_zero(Matrix1(dq.real().w()), tol) 34 | && almost_zero(Matrix1(dq.dual().w()), tol); 35 | } 36 | 37 | template 38 | bool 39 | is_unit(const DualQuaternion& dq, T tol) 40 | { 41 | using Matrix1 = Eigen::Matrix; 42 | 43 | return almost_equal(Matrix1(dq.real().squaredNorm()), Matrix1(T(1)), tol) 44 | && almost_equal(Matrix1(dq.real().dot(dq.dual())), Matrix1(T(0)), tol); 45 | } 46 | 47 | } // namespace dualquat 48 | -------------------------------------------------------------------------------- /odom_estimation_pc/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | odom_estimation_pc 4 | 0.0.0 5 | 6 | 7 | This work is created based to Floam (Fast and Optimized Lidar Odometry And Mapping) 8 | 9 | 10 | EPVS 11 | 12 | BSD 13 | EPVelasco 14 | 15 | catkin 16 | geometry_msgs 17 | nav_msgs 18 | roscpp 19 | rospy 20 | std_msgs 21 | rosbag 22 | sensor_msgs 23 | tf 24 | eigen_conversions 25 | geometry_msgs 26 | nav_msgs 27 | sensor_msgs 28 | roscpp 29 | rospy 30 | std_msgs 31 | rosbag 32 | tf 33 | eigen_conversions 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /dualquat_LOAM/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | dualquat_loam 4 | 0.0.0 5 | 6 | 7 | This work is created based to Floam (Fast and Optimized Lidar Odometry And Mapping) and STD descriptors 8 | 9 | 10 | EPVS 11 | 12 | BSD 13 | EPVelasco 14 | 15 | catkin 16 | geometry_msgs 17 | nav_msgs 18 | roscpp 19 | rospy 20 | std_msgs 21 | rosbag 22 | sensor_msgs 23 | tf 24 | eigen_conversions 25 | geometry_msgs 26 | nav_msgs 27 | sensor_msgs 28 | roscpp 29 | rospy 30 | std_msgs 31 | rosbag 32 | tf 33 | eigen_conversions 34 | ceres-solver 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /odom_estimation_pc/launch/odomEstimation_ouster.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /odom_estimation_pc/launch/odomEstimation_ouster_lite.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /odom_estimation_pc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.2) 2 | project(odom_estimation_pc) 3 | 4 | set(CMAKE_BUILD_TYPE "Release") 5 | set(CMAKE_CXX_FLAGS "-std=c++14") 6 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g") 7 | 8 | find_package(catkin REQUIRED COMPONENTS 9 | eigen_conversions 10 | geometry_msgs 11 | nav_msgs 12 | rosbag 13 | roscpp 14 | rospy 15 | sensor_msgs 16 | std_msgs 17 | tf 18 | ) 19 | 20 | 21 | find_package(Eigen3) 22 | if(NOT EIGEN3_FOUND) 23 | find_package(cmake_modules REQUIRED) 24 | find_package(Eigen REQUIRED) 25 | set(EIGEN3_INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}) 26 | set(EIGEN3_LIBRARIES ${EIGEN_LIBRARIES}) 27 | else() 28 | set(EIGEN3_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR}) 29 | endif() 30 | 31 | find_package(PCL REQUIRED) 32 | find_package(Ceres REQUIRED) 33 | 34 | include_directories( 35 | include 36 | ${catkin_INCLUDE_DIRS} 37 | ${PCL_INCLUDE_DIRS} 38 | ${CERES_INCLUDE_DIRS} 39 | ${EIGEN3_INCLUDE_DIRS} 40 | ) 41 | 42 | link_directories( 43 | include 44 | ${PCL_LIBRARY_DIRS} 45 | ${CERES_LIBRARY_DIRS} 46 | ) 47 | 48 | catkin_package( 49 | CATKIN_DEPENDS geometry_msgs nav_msgs roscpp rospy std_msgs 50 | DEPENDS EIGEN3 PCL Ceres 51 | INCLUDE_DIRS include 52 | ) 53 | 54 | add_executable(odom_estimation_node src/odomEstimationNode.cpp src/lidarOptimization.cpp src/lidar.cpp src/odomEstimationClass.cpp) 55 | target_link_libraries(odom_estimation_node ${EIGEN3_LIBRARIES} ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${CERES_LIBRARIES}) 56 | -------------------------------------------------------------------------------- /odom_estimation_pc/launch/odomEstimation_carla.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/quat_relational.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/quat_relational.h 3 | * @brief This file provides relational functions for quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include "relational.h" 9 | 10 | namespace dualquat 11 | { 12 | 13 | template 14 | bool almost_equal(const Quaternion& lhs, const Quaternion& rhs, T rtol, T atol) 15 | { 16 | return almost_equal(lhs.coeffs(), rhs.coeffs(), rtol, atol); 17 | } 18 | 19 | template 20 | bool almost_equal(const Quaternion& lhs, const Quaternion& rhs, T tol) 21 | { 22 | return almost_equal(lhs.coeffs(), rhs.coeffs(), tol); 23 | } 24 | 25 | template 26 | bool almost_zero(const Quaternion& q, T tol) 27 | { 28 | return almost_zero(q.coeffs(), tol); 29 | } 30 | 31 | /** 32 | * Returns true if the two quaternions represent the same rotation. 33 | * Note that every rotation is represented by two values, q and -q. 34 | */ 35 | template 36 | bool same_rotation(const Quaternion& lhs, const Quaternion& rhs, T tol) 37 | { 38 | #ifndef NDEBUG 39 | using Matrix1 = Eigen::Matrix; 40 | #endif 41 | assert(almost_equal(Matrix1(lhs.squaredNorm()), Matrix1(T(1)), tol)); 42 | assert(almost_equal(Matrix1(rhs.squaredNorm()), Matrix1(T(1)), tol)); 43 | 44 | using Coefficients = typename Quaternion::Coefficients; 45 | 46 | return almost_equal(lhs.coeffs(), rhs.coeffs(), tol) 47 | || almost_equal(lhs.coeffs(), Coefficients(-rhs.coeffs()), tol); 48 | } 49 | 50 | } // namespace dualquat 51 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_relational.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_relational.h 3 | * @brief This file provides relational functions for dual quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include "quat_relational.h" 9 | #include "dualquat_query.h" 10 | 11 | namespace dualquat 12 | { 13 | 14 | template 15 | bool almost_equal(const DualQuaternion& lhs, const DualQuaternion& rhs, T rtol, T atol) 16 | { 17 | return almost_equal(lhs.real().coeffs(), rhs.real().coeffs(), rtol, atol) 18 | && almost_equal(lhs.dual().coeffs(), rhs.dual().coeffs(), rtol, atol); 19 | } 20 | 21 | template 22 | bool almost_equal(const DualQuaternion& lhs, const DualQuaternion& rhs, T tol) 23 | { 24 | return almost_equal(lhs.real().coeffs(), rhs.real().coeffs(), tol) 25 | && almost_equal(lhs.dual().coeffs(), rhs.dual().coeffs(), tol); 26 | } 27 | 28 | template 29 | bool almost_zero(const DualQuaternion& dq, T tol) 30 | { 31 | return almost_zero(dq.real().coeffs(), tol) 32 | && almost_zero(dq.dual().coeffs(), tol); 33 | } 34 | 35 | /** 36 | * Returns true if the two dual quaternions represent the same transformation. 37 | * Note that every transformation is represented by two values, dq and -dq. 38 | */ 39 | template 40 | bool same_transformation(const DualQuaternion& lhs, const DualQuaternion& rhs, T tol) 41 | { 42 | assert(is_unit(lhs, tol)); 43 | assert(is_unit(rhs, tol)); 44 | 45 | return almost_equal(lhs, rhs, tol) 46 | || almost_equal(lhs, -rhs, tol); 47 | } 48 | 49 | } // namespace dualquat 50 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/relational.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/relational.h 3 | * @brief This file provides relational functions for DenseBase types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace dualquat 10 | { 11 | 12 | /** 13 | * Returns true if two matrices are element-wise equal within tolerance. 14 | */ 15 | template 16 | bool almost_equal( 17 | const Eigen::MatrixBase& lhs, 18 | const Eigen::MatrixBase& rhs, 19 | const typename DerivedA::RealScalar& rel_tolerance, 20 | const typename DerivedA::RealScalar& abs_tolerance) 21 | { 22 | return ((lhs - rhs).array().abs() 23 | <= Eigen::MatrixBase::Constant(abs_tolerance).array().max(rel_tolerance * lhs.array().abs().max(rhs.array().abs()))).all(); 24 | } 25 | 26 | /** 27 | * Returns true if two matrices are element-wise equal within tolerance. 28 | */ 29 | template 30 | bool almost_equal( 31 | const Eigen::MatrixBase& lhs, 32 | const Eigen::MatrixBase& rhs, 33 | const typename DerivedA::RealScalar& tolerance) 34 | { 35 | return ((lhs - rhs).array().abs() 36 | <= tolerance * Eigen::MatrixBase::Ones().array().max(lhs.array().abs().max(rhs.array().abs()))).all(); 37 | } 38 | 39 | /** 40 | * Returns true if a matrix is element-wise equal to zero within tolerance. 41 | */ 42 | template 43 | bool almost_zero( 44 | const Eigen::MatrixBase& x, 45 | const typename Derived::RealScalar& tolerance) 46 | { 47 | return (x.array().abs() <= tolerance).all(); 48 | } 49 | 50 | } // namespace dualquat 51 | -------------------------------------------------------------------------------- /odom_estimation_pc/launch/odomEstimation_VLP16.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /odom_estimation_pc/launch/odomEstimation_KITTI_dataset.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/laserMappingClass.h: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | #ifndef _LASER_MAPPING_H_ 6 | #define _LASER_MAPPING_H_ 7 | 8 | //PCL lib 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //eigen lib 17 | #include 18 | #include 19 | 20 | //c++ lib 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | #define LASER_CELL_WIDTH 200.0 27 | #define LASER_CELL_HEIGHT 200.0 28 | #define LASER_CELL_DEPTH 200.0 29 | 30 | //separate map as many sub point clouds 31 | 32 | #define LASER_CELL_RANGE_HORIZONTAL 20 33 | #define LASER_CELL_RANGE_VERTICAL 20 34 | 35 | 36 | class LaserMappingClass 37 | { 38 | 39 | public: 40 | LaserMappingClass(); 41 | void init(double map_resolution); 42 | void updateCurrentPointsToMap(const pcl::PointCloud::Ptr& pc_in, const Eigen::Isometry3d& pose_current); 43 | pcl::PointCloud::Ptr getMap(void); 44 | 45 | private: 46 | int origin_in_map_x; 47 | int origin_in_map_y; 48 | int origin_in_map_z; 49 | int map_width; 50 | int map_height; 51 | int map_depth; 52 | std::vector::Ptr>>> map; 53 | pcl::VoxelGrid downSizeFilter; 54 | 55 | void addWidthCellNegative(void); 56 | void addWidthCellPositive(void); 57 | void addHeightCellNegative(void); 58 | void addHeightCellPositive(void); 59 | void addDepthCellNegative(void); 60 | void addDepthCellPositive(void); 61 | void checkPoints(int& x, int& y, int& z); 62 | 63 | }; 64 | 65 | 66 | #endif // _LASER_MAPPING_H_ 67 | 68 | -------------------------------------------------------------------------------- /odom_estimation_pc/include/lidarOptimization.h: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | // Author of Lilo: Edison Velasco 6 | // Email evs25@alu.ua.es 7 | 8 | #ifndef _LIDAR_OPTIMIZATION_ANALYTIC_H_ 9 | #define _LIDAR_OPTIMIZATION_ANALYTIC_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | void getTransformFromSe3(const Eigen::Matrix& se3, Eigen::Quaterniond& q, Eigen::Vector3d& t); 17 | 18 | Eigen::Matrix3d skew(Eigen::Vector3d& mat_in); 19 | 20 | class EdgeAnalyticCostFunction : public ceres::SizedCostFunction<1, 7> { 21 | public: 22 | 23 | EdgeAnalyticCostFunction(Eigen::Vector3d curr_point_, Eigen::Vector3d last_point_a_, Eigen::Vector3d last_point_b_); 24 | virtual ~EdgeAnalyticCostFunction() {} 25 | virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const; 26 | 27 | Eigen::Vector3d curr_point; 28 | Eigen::Vector3d last_point_a; 29 | Eigen::Vector3d last_point_b; 30 | }; 31 | 32 | class SurfNormAnalyticCostFunction : public ceres::SizedCostFunction<1, 7> { 33 | public: 34 | SurfNormAnalyticCostFunction(Eigen::Vector3d curr_point_, Eigen::Vector3d plane_unit_norm_, double negative_OA_dot_norm_); 35 | virtual ~SurfNormAnalyticCostFunction() {} 36 | virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const; 37 | 38 | Eigen::Vector3d curr_point; 39 | Eigen::Vector3d plane_unit_norm; 40 | double negative_OA_dot_norm; 41 | }; 42 | 43 | class PoseSE3Parameterization : public ceres::LocalParameterization { 44 | public: 45 | 46 | PoseSE3Parameterization() {} 47 | virtual ~PoseSE3Parameterization() {} 48 | virtual bool Plus(const double* x, const double* delta, double* x_plus_delta) const; 49 | virtual bool ComputeJacobian(const double* x, double* jacobian) const; 50 | virtual int GlobalSize() const { return 7; } 51 | virtual int LocalSize() const { return 6; } 52 | }; 53 | 54 | 55 | 56 | #endif // _LIDAR_OPTIMIZATION_ANALYTIC_H_ 57 | 58 | -------------------------------------------------------------------------------- /gps_to_odom/cfg/GpsToOdom.cfg: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #* All rights reserved. 3 | #* 4 | #* Redistribution and use in source and binary forms, with or without 5 | #* modification, are permitted provided that the following conditions 6 | #* are met: 7 | #* 8 | #* * Redistributions of source code must retain the above copyright 9 | #* notice, this list of conditions and the following disclaimer. 10 | #* * Redistributions in binary form must reproduce the above 11 | #* copyright notice, this list of conditions and the following 12 | #* disclaimer in the documentation and/or other materials provided 13 | #* with the distribution. 14 | #* * Neither the name of the Willow Garage nor the names of its 15 | #* contributors may be used to endorse or promote products derived 16 | #* from this software without specific prior written permission. 17 | #* 18 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | #* POSSIBILITY OF SUCH DAMAGE. 30 | #*********************************************************** 31 | 32 | # Author: 33 | 34 | PACKAGE='gps_to_odom' 35 | 36 | from dynamic_reconfigure.parameter_generator_catkin import * 37 | 38 | gen = ParameterGenerator() 39 | 40 | # Name Type Reconfiguration level Description Default Min Max 41 | #gen.add("velocity_scale_factor", double_t, 0, "Maximum velocity scale factor", 0.5, 0.0, 1.0) 42 | 43 | exit(gen.generate(PACKAGE, "GpsToOdomAlgorithm", "GpsToOdom")) 44 | -------------------------------------------------------------------------------- /ackermann_to_odom/cfg/AckermannToOdom.cfg: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #* All rights reserved. 3 | #* 4 | #* Redistribution and use in source and binary forms, with or without 5 | #* modification, are permitted provided that the following conditions 6 | #* are met: 7 | #* 8 | #* * Redistributions of source code must retain the above copyright 9 | #* notice, this list of conditions and the following disclaimer. 10 | #* * Redistributions in binary form must reproduce the above 11 | #* copyright notice, this list of conditions and the following 12 | #* disclaimer in the documentation and/or other materials provided 13 | #* with the distribution. 14 | #* * Neither the name of the Willow Garage nor the names of its 15 | #* contributors may be used to endorse or promote products derived 16 | #* from this software without specific prior written permission. 17 | #* 18 | #* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | #* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | #* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | #* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | #* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | #* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | #* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | #* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | #* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | #* POSSIBILITY OF SUCH DAMAGE. 30 | #*********************************************************** 31 | 32 | # Author: 33 | 34 | PACKAGE='ackermann_to_odom' 35 | 36 | from dynamic_reconfigure.parameter_generator_catkin import * 37 | 38 | gen = ParameterGenerator() 39 | 40 | # Name Type Reconfiguration level Description Default Min Max 41 | #gen.add("velocity_scale_factor", double_t, 0, "Maximum velocity scale factor", 0.5, 0.0, 1.0) 42 | 43 | exit(gen.generate(PACKAGE, "AckermannToOdomAlgorithm", "AckermannToOdom")) 44 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_exponential.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_exponential.h 3 | * @brief This file provides exponential functions for dual quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include "quat_exponential.h" 9 | 10 | namespace dualquat 11 | { 12 | 13 | /** 14 | * Returns a exponential of a dual quaternion. 15 | */ 16 | template 17 | DualQuaternion 18 | exp(const DualQuaternion& dq) 19 | { 20 | DualQuaternion temp; 21 | temp.real() = dualquat::exp(dq.real()); 22 | 23 | T sinc, alpha; 24 | const auto vn = dq.real().vec().norm(); 25 | if(vn > T(0)) 26 | { 27 | sinc = std::sin(vn) / vn; 28 | alpha = (std::cos(vn) - sinc) / (vn * vn); 29 | } 30 | else 31 | { 32 | sinc = T(1); 33 | alpha = - T(1) / T(3); 34 | } 35 | 36 | const auto vdot = dq.real().vec().dot(dq.dual().vec()); 37 | 38 | temp.dual().w() = - vdot * sinc; 39 | temp.dual().vec() = sinc * dq.dual().vec() + vdot * alpha * dq.real().vec(); 40 | temp.dual().coeffs() = std::exp(dq.real().w()) * temp.dual().coeffs() + dq.dual().w() * temp.real().coeffs(); 41 | 42 | return temp; 43 | } 44 | 45 | /** 46 | * Returns a logarithm of a dual quaternion. 47 | */ 48 | template 49 | DualQuaternion 50 | log(const DualQuaternion& dq) 51 | { 52 | DualQuaternion temp; 53 | temp.real() = dualquat::log(dq.real()); 54 | 55 | T phi_over_vn, alpha; 56 | const auto vn = dq.real().vec().norm(); 57 | const auto phi = std::atan2(vn, dq.real().w()); 58 | const auto qn = dq.real().norm(); 59 | if(vn > T(0)) 60 | { 61 | phi_over_vn = phi / vn; 62 | alpha = (dq.real().w() - phi_over_vn * qn * qn) / (vn * vn); 63 | } 64 | else 65 | { 66 | phi_over_vn = T(1) / qn; 67 | alpha = (- T(2) / T(3)) / qn; 68 | } 69 | 70 | temp.dual().w() = dq.real().dot(dq.dual()) / (qn * qn); 71 | temp.dual().vec() = phi_over_vn * dq.dual().vec() 72 | + ((dq.real().vec().dot(dq.dual().vec()) * alpha - dq.dual().w()) / (qn * qn)) * dq.real().vec(); 73 | 74 | return temp; 75 | } 76 | 77 | /** 78 | * Returns a dual quaternion raised to a power. 79 | */ 80 | template 81 | DualQuaternion 82 | pow(const DualQuaternion& dq, T t) 83 | { 84 | return exp(t * log(dq)); 85 | } 86 | 87 | } // namespace dualquat 88 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_HeLiPR_display_STD.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_HeLiPR_dataset.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_hensai.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_KITTI_dataset.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_NTU_dataset.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /aurova_odom/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | aurova_odom 4 | 1.0.0 5 | The aurova_odom package 6 | 7 | 8 | 9 | 10 | mice85 11 | 12 | 13 | 14 | 15 | 16 | LGPL 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ackermann_to_odom 53 | gps_to_odom 54 | odom_estimation_pc 55 | 56 | 57 | catkin 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_KITTI_display_STD.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_conSLAM_dataset.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_common.h 3 | * @brief This file provides common functions for dual quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace dualquat 10 | { 11 | 12 | /* Dual-valued functions */ 13 | 14 | template 15 | std::pair 16 | norm(const DualQuaternion& dq) 17 | { 18 | const auto n = dq.real().norm(); 19 | return std::make_pair(n, dq.real().dot(dq.dual()) / n); 20 | } 21 | 22 | template 23 | std::pair 24 | squared_norm(const DualQuaternion& dq) 25 | { 26 | return std::make_pair(dq.real().squaredNorm(), T(2) * dq.real().dot(dq.dual())); 27 | } 28 | 29 | /* DualQuaternion-valued functions */ 30 | 31 | template 32 | DualQuaternion 33 | identity() 34 | { 35 | return DualQuaternion( 36 | Quaternion::Identity(), 37 | Quaternion(Quaternion::Coefficients::Zero())); 38 | } 39 | 40 | template 41 | DualQuaternion 42 | inverse(const DualQuaternion& dq) 43 | { 44 | const auto inv_real = dq.real().inverse(); 45 | 46 | DualQuaternion temp; 47 | temp.real() = inv_real; 48 | temp.dual() = -(inv_real * dq.dual() * inv_real).coeffs(); 49 | return temp; 50 | } 51 | 52 | template 53 | DualQuaternion 54 | normalize(const DualQuaternion& dq) 55 | { 56 | const auto r = dq.real().normalized(); 57 | const auto d = dq.dual().coeffs() / dq.real().norm(); 58 | 59 | DualQuaternion temp; 60 | temp.real() = r; 61 | temp.dual() = d - r.coeffs().dot(d) * r.coeffs(); 62 | return temp; 63 | } 64 | 65 | /** 66 | * Dual-conjugate. 67 | */ 68 | template 69 | DualQuaternion 70 | dual_conjugate(const DualQuaternion& dq) 71 | { 72 | DualQuaternion temp(dq); 73 | temp.dual().coeffs() = -temp.dual().coeffs(); 74 | return temp; 75 | } 76 | 77 | /** 78 | * Quaternion-conjugate. 79 | */ 80 | template 81 | DualQuaternion 82 | quaternion_conjugate(const DualQuaternion& dq) 83 | { 84 | return DualQuaternion(dq.real().conjugate(), dq.dual().conjugate()); 85 | } 86 | 87 | /** 88 | * Total-conjugate. 89 | */ 90 | template 91 | DualQuaternion 92 | total_conjugate(const DualQuaternion& dq) 93 | { 94 | DualQuaternion temp(dq.real().conjugate(), dq.dual().conjugate()); 95 | temp.dual().coeffs() = -temp.dual().coeffs(); 96 | return temp; 97 | } 98 | 99 | /** 100 | * Returns the difference between the two dual quaternions. 101 | */ 102 | template 103 | DualQuaternion 104 | difference(const DualQuaternion& dq1, const DualQuaternion& dq2) 105 | { 106 | return inverse(dq1) * dq2; 107 | } 108 | 109 | } // namespace dualquat 110 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_ouster_BLUE_dataset.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /dualquat_LOAM/launch/odomEstimation_ouster_BLUE_display_std.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /gps_to_odom/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | gps_to_odom 4 | 0.0.0 5 | The gps_to_odom package 6 | 7 | 8 | 9 | 10 | mice85 11 | 12 | 13 | 14 | 15 | 16 | LGPL 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | catkin 52 | 53 | iri_base_algorithm 54 | tf 55 | 56 | iri_base_algorithm 57 | tf 58 | 59 | iri_base_algorithm 60 | tf 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ackermann_to_odom/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ackermann_to_odom 4 | 1.0.0 5 | The ackermann_to_odom package 6 | 7 | 8 | 9 | 10 | mice85 11 | 12 | 13 | 14 | 15 | 16 | LGPL 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | catkin 52 | 53 | iri_base_algorithm 54 | tf 55 | 56 | iri_base_algorithm 57 | tf 58 | 59 | iri_base_algorithm 60 | tf 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_helper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_helper.h 3 | * @brief This file provides helper functions for dual quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include "dualquat_common.h" 10 | #include "dualquat_exponential.h" 11 | 12 | namespace dualquat 13 | { 14 | 15 | /** 16 | * Conversion from screw parameters to a dual quaternion. 17 | * @param [in] l The direction vector of the screw axis. 18 | * @param [in] m The moment vector of the screw axis. 19 | * @param [in] theta The angle of rotation in radians around the screw axis. 20 | * @param [in] d Displacement along the screw axis. 21 | */ 22 | template 23 | DualQuaternion 24 | convert_to_dualquat(const Vector3& l, const Vector3& m, T theta, T d) 25 | { 26 | const auto half_theta = T(0.5) * theta; 27 | const auto half_d = T(0.5) * d; 28 | const auto sine = std::sin(half_theta); 29 | 30 | DualQuaternion temp; 31 | temp.real() = Eigen::AngleAxis(theta, l); 32 | temp.dual().w() = -half_d * sine; 33 | temp.dual().vec() = sine * m + half_d * std::cos(half_theta) * l; 34 | return temp; 35 | } 36 | 37 | /** 38 | * Conversion from a dual quaternion to screw parameters. 39 | * @param [in] dq A dual quaternion representing a transformation. 40 | */ 41 | template 42 | std::tuple, Vector3, T, T> 43 | convert_to_screw(const DualQuaternion& dq) 44 | { 45 | const auto half_theta = std::acos(dq.real().w()); 46 | const auto theta = T(2) * half_theta; 47 | const Vector3 l = dq.real().vec() / std::sin(half_theta); 48 | const Vector3 t = T(2) * (dq.dual() * dq.real().conjugate()).vec(); 49 | const auto d = t.dot(l); 50 | const Vector3 m = T(0.5) * (t.cross(l) + (t - d * l) * std::tan(half_theta)); 51 | return std::make_tuple(l, m, theta, d); 52 | } 53 | 54 | /** 55 | * Screw linear interpolation. 56 | * @param [in] dq1 Unit Dual Quaternion as a start point for interpolation. 57 | * @param [in] dq2 Unit Dual Quaternion as an end point for interpolation. 58 | * @param [in] t Value varies between 0 and 1. 59 | */ 60 | template 61 | DualQuaternion 62 | sclerp(const DualQuaternion& dq1, const DualQuaternion& dq2, T t) 63 | { 64 | return dq1 * pow(quaternion_conjugate(dq1) * dq2, t); 65 | } 66 | 67 | /** 68 | * Screw linear interpolation. 69 | * @param [in] dq1 Unit Dual Quaternion as a start point for interpolation. 70 | * @param [in] dq2 Unit Dual Quaternion as an end point for interpolation. 71 | * @param [in] t Value varies between 0 and 1. 72 | */ 73 | template 74 | DualQuaternion 75 | sclerp_shortestpath(const DualQuaternion& dq1, const DualQuaternion& dq2, T t) 76 | { 77 | const auto cos_half_angle = dq1.real().dot(dq2.real()); 78 | const auto diff = quaternion_conjugate(dq1) * (cos_half_angle < T(0) ? -dq2 : dq2); 79 | return dq1 * pow(diff, t); 80 | } 81 | 82 | } // namespace dualquat 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Example of usage: 2 | 3 | You can run an example following the instructions in [applications](https://github.com/AUROVA-LAB/applications) (Examples). 4 | 5 | # aurova_odom 6 | This is a metapackage that contains different packages that perform different kind of odometry nodes. Compiling this metapackage into ROS will compile all the packages at once. This metapackage is grouped as a project for eclipse C++. Each package contains a "name_doxygen_config" configuration file for generate doxygen documentation. The packages contained in this metapackage are: 7 | 8 | **gps_to_odom** 9 | This package contains a node that, as input, reads the topics /fix, of type sensor_msgs::NavSatFix, and /rover/fix_velocity of type geometry_msgs::TwistWithCovariance (if from gazebo /fix_vel of type geometry_msgs::Vector3Stamped). This node transform gps location from /fix in utm frame to a frame defined in ~gps_to_odom/frame_id. Also calculates the orientation using the velocities from gps, and generate new odometry (message type nav_msgs::Odometry). This message is published in output topic called /odometry_gps. 10 | 11 | Parameters: 12 | * ~gps_to_odom/frame_id (default: ""): This is the frame to transform from utm (usually set as "map"). 13 | * ~gps_to_odom/min_speed (default: null): This is used as a threshold. Under this velocity, the orientation is not computed from the GPS velocity message. 14 | * ~gps_to_odom/max_speed (default: null): We add additive variance to the orientation message inversely proportional to this parameter. 15 | 16 | **ackermann_to_odom** 17 | This package contains a node that, as input, reads the topics /estimated_ackermann_state and /covariance_ackermann_state, of type ackermann_msgs::AckermannDriveStamped, and /virtual_imu_data of type sensor_msgs::Imu. This node parse this information as a new message type nav_msgs::Odometry using the 2D tricicle model. This message is published in an output topic called /odometry. 18 | 19 | Parameters: 20 | * ~odom_in_tf (default: false): If this parameter is set to true, the odometry is also published in /tf topic. 21 | * ~scan_in_tf (default: false): If this parameter is set to true, the laser transform read from the static robot transformation is published in /tf topic. 22 | * ~frame_id (default: ""): This parameter is the name of frame to transform if scan_in_tf is true. 23 | * ~child_id (default: ""): This parameter is the name of child frame to transform if scan_in_tf is true. 24 | 25 | **odom_estimation_pc** (**LiLO**->Lite LiDAR Odometry method based on SRI) 26 | 27 | This package estimates odometry from a point cloud segmented into edges and surface. The package works in conjunction with [pc2image](https://github.com/AUROVA-LAB/aurova_preprocessed/tree/master/pc2image), which converts a point cloud into an SRI range image and filters it to extract the desired features. 28 | As input topics are required: 29 | * /pcl_edge : Topic by which the edge point cloud is subscribed to. 30 | * /pcl_surf: Topic to subscribe to the surface point cloud. 31 | As output topic are: 32 | */odom: Topic that has the estimated odometry. 33 | 34 | Parameters: 35 | * ~/target_frame_name (default: "odom") 36 | * ~/source_frame_name (default: "base_link") 37 | * ~/clear_map (default: "false") : This paramater enable the clear map funtion. 38 | * ~/childframeID (default: ""): This parameter is the name of child frame to transform. 39 | -------------------------------------------------------------------------------- /dualquat_LOAM/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.2) 2 | project(dualquat_loam) 3 | 4 | ## Compile as C++14 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_EXTENSIONS OFF) 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_BUILD_TYPE "Release") 9 | set(CMAKE_CXX_FLAGS "-std=c++14") 10 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g") 11 | 12 | message("Current CPU archtecture: ${CMAKE_SYSTEM_PROCESSOR}") 13 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)" ) 14 | include(ProcessorCount) 15 | ProcessorCount(N) 16 | message("Processer number: ${N}") 17 | if(N GREATER 5) 18 | add_definitions(-DMP_EN) 19 | add_definitions(-DMP_PROC_NUM=4) 20 | message("core for MP: 4") 21 | elseif(N GREATER 3) 22 | math(EXPR PROC_NUM "${N} - 2") 23 | add_definitions(-DMP_EN) 24 | add_definitions(-DMP_PROC_NUM="${PROC_NUM}") 25 | message("core for MP: ${PROC_NUM}") 26 | else() 27 | add_definitions(-DMP_PROC_NUM=1) 28 | endif() 29 | else() 30 | add_definitions(-DMP_PROC_NUM=1) 31 | endif() 32 | 33 | # Find nanoflannConfig.cmake: 34 | find_package(nanoflann) 35 | include_directories("/home/ws/src/nanoflann/include") 36 | 37 | find_package(catkin REQUIRED COMPONENTS 38 | eigen_conversions 39 | geometry_msgs 40 | nav_msgs 41 | rosbag 42 | roscpp 43 | rospy 44 | sensor_msgs 45 | std_msgs 46 | tf 47 | pcl_conversions 48 | pcl_ros 49 | tf_conversions 50 | 51 | ) 52 | 53 | include_directories( "/usr/include/dqrobotics" ) 54 | 55 | find_package(Eigen3) 56 | if(NOT EIGEN3_FOUND) 57 | find_package(cmake_modules REQUIRED) 58 | find_package(Eigen REQUIRED) 59 | set(EIGEN3_INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}) 60 | set(EIGEN3_LIBRARIES ${EIGEN_LIBRARIES}) 61 | else() 62 | set(EIGEN3_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR}) 63 | endif() 64 | 65 | ## System dependencies are found with CMake's conventions 66 | find_package(OpenMP QUIET) 67 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 68 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 69 | find_package(PCL REQUIRED) 70 | find_package(Ceres REQUIRED) 71 | find_package(GTSAM REQUIRED QUIET) 72 | 73 | set(CMAKE_AUTOMOC ON) 74 | set(CMAKE_AUTOUIC ON) 75 | set(CMAKE_AUTORCC ON) 76 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 77 | 78 | 79 | include_directories( 80 | include 81 | ${catkin_INCLUDE_DIRS} 82 | ${PCL_INCLUDE_DIRS} 83 | ${CERES_INCLUDE_DIRS} 84 | ${EIGEN3_INCLUDE_DIRS} 85 | ) 86 | 87 | link_directories( 88 | include 89 | ${PCL_LIBRARY_DIRS} 90 | ${CERES_LIBRARY_DIRS} 91 | ) 92 | 93 | catkin_package( 94 | CATKIN_DEPENDS geometry_msgs nav_msgs roscpp rospy std_msgs 95 | DEPENDS EIGEN3 PCL Ceres 96 | INCLUDE_DIRS include 97 | ) 98 | 99 | add_executable(dq_pose_estimation_node src/odomEstimationNode.cpp src/odomEstimationClass.cpp src/STDesc.cpp src/KDTree_STD.cpp) 100 | target_link_libraries(dq_pose_estimation_node ${EIGEN3_LIBRARIES} ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${CERES_LIBRARIES} dqrobotics) 101 | 102 | add_executable(laser_mapping src/laserMappingNode.cpp src/laserMappingClass.cpp) 103 | target_link_libraries(laser_mapping ${EIGEN3_LIBRARIES} ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${CERES_LIBRARIES} dqrobotics) 104 | 105 | add_executable(std_extractor src/std_extractor.cpp src/STDesc.cpp src/KDTree_STD.cpp) 106 | target_link_libraries(std_extractor 107 | ${catkin_LIBRARIES} 108 | ${PCL_LIBRARIES} 109 | ${OpenCV_LIBS} 110 | ${CERES_LIBRARIES}) 111 | 112 | -------------------------------------------------------------------------------- /odom_estimation_pc/include/odomEstimationClass.h: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | // Author of Lilo: Edison Velasco 6 | // Email evs25@alu.ua.es 7 | 8 | #ifndef _ODOM_ESTIMATION_CLASS_H_ 9 | #define _ODOM_ESTIMATION_CLASS_H_ 10 | 11 | //std lib 12 | #include 13 | #include 14 | #include 15 | 16 | //PCL 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | //ceres 28 | #include 29 | #include 30 | 31 | //eigen 32 | #include 33 | #include 34 | 35 | //LOCAL LIB 36 | #include "lidar.h" 37 | #include "lidarOptimization.h" 38 | #include 39 | 40 | class OdomEstimationClass 41 | { 42 | 43 | public: 44 | OdomEstimationClass(); 45 | 46 | void init(lidar::Lidar lidar_param, double edge_resolution,double surf_resolution); 47 | void initMapWithPoints(const pcl::PointCloud::Ptr& edge_in, const pcl::PointCloud::Ptr& surf_in); 48 | void updatePointsToMap(const pcl::PointCloud::Ptr& edge_in, const pcl::PointCloud::Ptr& surf_in, bool clear_map ,double cropBox_len); 49 | void getMap(pcl::PointCloud::Ptr& laserCloudMap); 50 | 51 | Eigen::Isometry3d odom; 52 | pcl::PointCloud::Ptr laserCloudCornerMap; 53 | pcl::PointCloud::Ptr laserCloudSurfMap; 54 | private: 55 | //optimization variable 56 | double parameters[7] = {0, 0, 0, 1, 0, 0, 0}; 57 | Eigen::Map q_w_curr = Eigen::Map(parameters); 58 | Eigen::Map t_w_curr = Eigen::Map(parameters + 4); 59 | 60 | Eigen::Isometry3d last_odom; 61 | 62 | //kd-tree 63 | pcl::KdTreeFLANN::Ptr kdtreeEdgeMap; 64 | pcl::KdTreeFLANN::Ptr kdtreeSurfMap; 65 | 66 | //points downsampling before add to map 67 | pcl::VoxelGrid downSizeFilterEdge; 68 | pcl::VoxelGrid downSizeFilterSurf; 69 | 70 | //local map 71 | pcl::CropBox cropBoxFilter; 72 | 73 | //optimization count 74 | int optimization_count; 75 | 76 | //function 77 | void addEdgeCostFactor(const pcl::PointCloud::Ptr& pc_in, const pcl::PointCloud::Ptr& map_in, ceres::Problem& problem, ceres::LossFunction *loss_function); 78 | void addSurfCostFactor(const pcl::PointCloud::Ptr& pc_in, const pcl::PointCloud::Ptr& map_in, ceres::Problem& problem, ceres::LossFunction *loss_function); 79 | void addPointsToMap(const pcl::PointCloud::Ptr& downsampledEdgeCloud, const pcl::PointCloud::Ptr& downsampledSurfCloud, bool clear_map, double cropBox_len); 80 | void pointAssociateToMap(pcl::PointXYZ const *const pi, pcl::PointXYZ *const po); 81 | void downSamplingToMap(const pcl::PointCloud::Ptr& edge_pc_in, pcl::PointCloud::Ptr& edge_pc_out, const pcl::PointCloud::Ptr& surf_pc_in, pcl::PointCloud::Ptr& surf_pc_out); 82 | void occlude_pcd(pcl::PointCloud::Ptr & cld_ptr,int dim, double threshA, double threshB); 83 | }; 84 | 85 | #endif // _ODOM_ESTIMATION_CLASS_H_ 86 | 87 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_transformation.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_transformation.h 3 | * @brief This file provides transformation functions for dual quaternion types. 4 | */ 5 | #pragma once 6 | 7 | #include "dualquat_common.h" 8 | 9 | namespace dualquat 10 | { 11 | 12 | /** 13 | * This transformation applies first the rotation and then the translation. 14 | */ 15 | template 16 | DualQuaternion 17 | transformation(const Quaternion& r, const Vector3& t) 18 | { 19 | auto dual = Quaternion(T(0), t.x(), t.y(), t.z()) * r; 20 | dual.coeffs() *= T(0.5); 21 | return DualQuaternion(r, dual); 22 | } 23 | 24 | /** 25 | * This transformation applies first the translation and then the rotation. 26 | */ 27 | template 28 | DualQuaternion 29 | transformation(const Vector3& t, const Quaternion& r) 30 | { 31 | auto dual = r * Quaternion(T(0), t.x(), t.y(), t.z()); 32 | dual.coeffs() *= T(0.5); 33 | return DualQuaternion(r, dual); 34 | } 35 | 36 | /** 37 | * This transformation applies pure rotation. 38 | */ 39 | template 40 | DualQuaternion 41 | transformation(const Quaternion& r) 42 | { 43 | return DualQuaternion( 44 | r, 45 | Quaternion(Quaternion::Coefficients::Zero())); 46 | } 47 | 48 | /** 49 | * This transformation applies pure translation. 50 | */ 51 | template 52 | DualQuaternion 53 | transformation(const Vector3& t) 54 | { 55 | auto dual = Quaternion(T(0), t.x(), t.y(), t.z()); 56 | dual.coeffs() *= T(0.5); 57 | return DualQuaternion(Quaternion::Identity(), dual); 58 | } 59 | 60 | /** 61 | * Returns the difference between the two dual quaternions representing the transformation. 62 | */ 63 | template 64 | DualQuaternion 65 | transformational_difference(const DualQuaternion& dq1, const DualQuaternion& dq2) 66 | { 67 | return quaternion_conjugate(dq1) * dq2; 68 | } 69 | 70 | /** 71 | * Transforms a point with a unit dual quaternion. 72 | * @param [in] dq A unit dual quaternion representing a transformation. 73 | * @param [in] p A point represented by a dual quaternion. 74 | */ 75 | template 76 | DualQuaternion 77 | transform_point(const DualQuaternion& dq, const DualQuaternion& p) 78 | { 79 | return dq * p * total_conjugate(dq); 80 | } 81 | 82 | /** 83 | * Transforms a point with a unit dual quaternion. 84 | * @see dualquat::transform_point() 85 | */ 86 | template 87 | DualQuaternion 88 | transform_point(const DualQuaternion& dq, const Vector3& p) 89 | { 90 | return transform_point(dq, DualQuaternion(p)); 91 | } 92 | 93 | /** 94 | * Transforms a line with a unit dual quaternion. 95 | * @param [in] dq A unit dual quaternion representing a transformation. 96 | * @param [in] l A line in the Plucker coordinates represented by a dual quaternion. 97 | */ 98 | template 99 | DualQuaternion 100 | transform_line(const DualQuaternion& dq, const DualQuaternion& l) 101 | { 102 | return dq * l * quaternion_conjugate(dq); 103 | } 104 | 105 | /** 106 | * Transforms a line with a unit dual quaternion. 107 | * @see dualquat::transform_line() 108 | */ 109 | template 110 | DualQuaternion 111 | transform_line(const DualQuaternion& dq, const Vector3& l, const Vector3& m) 112 | { 113 | return transform_line(dq, DualQuaternion(l, m)); 114 | } 115 | 116 | } // namespace dualquat 117 | -------------------------------------------------------------------------------- /dualquat_LOAM/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM osrf/ros:noetic-desktop-focal 2 | 3 | # install ros packages 4 | RUN apt-get update && apt-get install -y --no-install-recommends \ 5 | ros-noetic-desktop-full=1.5.0-1* \ 6 | && rm -rf /var/lib/apt/lists/* 7 | 8 | ENV DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update && apt-get install -y apt-utils curl wget git bash-completion build-essential sudo && rm -rf /var/lib/apt/lists/* 11 | 12 | # Now create the user 13 | ARG UID=1000 14 | ARG GID=1000 15 | RUN addgroup --gid ${GID} docker 16 | RUN adduser --gecos "ROS User" --disabled-password --uid ${UID} --gid ${GID} docker 17 | RUN usermod -a -G dialout docker 18 | RUN mkdir config && echo "ros ALL=(ALL) NOPASSWD: ALL" > config/99_aptget 19 | RUN cp config/99_aptget /etc/sudoers.d/99_aptget 20 | RUN chmod 0440 /etc/sudoers.d/99_aptget && chown root:root /etc/sudoers.d/99_aptget 21 | 22 | RUN apt-get update && apt-get install -y apt-utils curl wget git bash-completion build-essential sudo && rm -rf /var/lib/apt/lists/* 23 | 24 | ENV HOME /home/docker 25 | RUN mkdir -p ${HOME}/catkin_ws/library 26 | 27 | # Install Ceres 28 | RUN apt-get update && apt-get install cmake libgoogle-glog-dev libgflags-dev libatlas-base-dev libeigen3-dev libsuitesparse-dev -y 29 | RUN cd ${HOME}/catkin_ws/library && wget http://ceres-solver.org/ceres-solver-2.2.0.tar.gz 30 | RUN cd ${HOME}/catkin_ws/library && tar zxf ceres-solver-2.2.0.tar.gz && cd ceres-solver-2.2.0 && mkdir ceres-bin && cd ceres-bin && cmake .. && cmake .. && make -j$(nproc) && make install 31 | 32 | 33 | # ########### 34 | 35 | # Lidar Odometry dependeces 36 | RUN apt-get update && \ 37 | apt-get install -y --no-install-recommends \ 38 | ros-noetic-hector-trajectory-server \ 39 | vim # extras tools 40 | 41 | 42 | RUN . /opt/ros/noetic/setup.sh && \ 43 | mkdir -p ${HOME}/catkin_ws/src && \ 44 | cd ${HOME}/catkin_ws/src 45 | 46 | 47 | # Install DQ library 48 | RUN apt-get update && \ 49 | apt-get install -y software-properties-common && \ 50 | add-apt-repository ppa:dqrobotics-dev/release && \ 51 | apt-get update 52 | 53 | # Instalar libdqrobotics 54 | RUN apt-get install -y libdqrobotics 55 | 56 | # STD dependences 57 | # Add PPA 58 | RUN add-apt-repository ppa:borglab/gtsam-release-4.0 59 | RUN apt update && apt install -y libgtsam-dev libgtsam-unstable-dev 60 | 61 | # install nanoflann 62 | RUN cd ${HOME}/catkin_ws/library && git clone https://github.com/EPVelasco/nanoflann.git && cd nanoflann && mkdir build && cd build && cmake .. && sudo make install 63 | 64 | # catkin_make dualquat_loam 65 | RUN mkdir ${HOME}/catkin_ws/src/dualquat_LOAM/ 66 | COPY . ${HOME}/catkin_ws/src/dualquat_LOAM/ 67 | RUN . /opt/ros/noetic/setup.sh && \ 68 | cd ${HOME}/catkin_ws/ && catkin_make --only-pkg-with-deps dualquat_loam 69 | 70 | 71 | # Install Aurova preprocessing 72 | RUN cd ${HOME}/catkin_ws/src/ && git clone https://github.com/AUROVA-LAB/aurova_preprocessed.git 73 | RUN . /opt/ros/noetic/setup.sh && \ 74 | cd ${HOME}/catkin_ws/ && catkin_make --only-pkg-with-deps pc_feature_extraction 75 | 76 | 77 | # bash update 78 | RUN echo "TERM=xterm-256color" >> ~/.bashrc 79 | RUN echo "# COLOR Text" >> ~/.bashrc 80 | RUN echo "PS1='\[\033[01;33m\]\u\[\033[01;33m\]@\[\033[01;33m\]\h\[\033[01;34m\]:\[\033[00m\]\[\033[01;34m\]\w\[\033[00m\]\$ '" >> ~/.bashrc 81 | RUN echo "CLICOLOR=1" >> ~/.bashrc 82 | RUN echo "LSCOLORS=GxFxCxDxBxegedabagaced" >> ~/.bashrc 83 | RUN echo "" >> ~/.bashrc 84 | RUN echo "## ROS" >> ~/.bashrc 85 | RUN echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc 86 | 87 | ############ 88 | # Configura la variable de entorno DISPLAYWORKDIR 89 | USER docker 90 | ENV DISPLAY=:0 91 | ENV NVIDIA_DRIVER_CAPABILITIES graphics,compute,utility 92 | WORKDIR ${HOME}/catkin_ws 93 | -------------------------------------------------------------------------------- /ackermann_to_odom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(ackermann_to_odom) 3 | 4 | ## Find catkin macros and libraries 5 | find_package(catkin REQUIRED) 6 | # ******************************************************************** 7 | # Add catkin additional components here 8 | # ******************************************************************** 9 | find_package(catkin REQUIRED COMPONENTS 10 | iri_base_algorithm 11 | tf 12 | ) 13 | 14 | ## System dependencies are found with CMake's conventions 15 | # find_package(Boost REQUIRED COMPONENTS system) 16 | 17 | # ******************************************************************** 18 | # Add system and labrobotica dependencies here 19 | # ******************************************************************** 20 | # find_package( REQUIRED) 21 | 22 | # ******************************************************************** 23 | # Add topic, service and action definition here 24 | # ******************************************************************** 25 | ## Generate messages in the 'msg' folder 26 | # add_message_files( 27 | # FILES 28 | # Message1.msg 29 | # Message2.msg 30 | # ) 31 | 32 | ## Generate services in the 'srv' folder 33 | # add_service_files( 34 | # FILES 35 | # Service1.srv 36 | # Service2.srv 37 | # ) 38 | 39 | ## Generate actions in the 'action' folder 40 | # add_action_files( 41 | # FILES 42 | # Action1.action 43 | # Action2.action 44 | # ) 45 | 46 | ## Generate added messages and services with any dependencies listed here 47 | # generate_messages( 48 | # DEPENDENCIES 49 | # std_msgs # Or other packages containing msgs 50 | # ) 51 | 52 | # ******************************************************************** 53 | # Add the dynamic reconfigure file 54 | # ******************************************************************** 55 | generate_dynamic_reconfigure_options(cfg/AckermannToOdom.cfg) 56 | 57 | # ******************************************************************** 58 | # Add run time dependencies here 59 | # ******************************************************************** 60 | catkin_package( 61 | # INCLUDE_DIRS 62 | # LIBRARIES 63 | # ******************************************************************** 64 | # Add ROS and IRI ROS run time dependencies 65 | # ******************************************************************** 66 | CATKIN_DEPENDS iri_base_algorithm 67 | # ******************************************************************** 68 | # Add system and labrobotica run time dependencies here 69 | # ******************************************************************** 70 | # DEPENDS 71 | ) 72 | 73 | ########### 74 | ## Build ## 75 | ########### 76 | 77 | # ******************************************************************** 78 | # Add the include directories 79 | # ******************************************************************** 80 | include_directories(include) 81 | include_directories(${catkin_INCLUDE_DIRS}) 82 | # include_directories(${_INCLUDE_DIR}) 83 | 84 | ## Declare a cpp library 85 | # add_library(${PROJECT_NAME} ) 86 | 87 | ## Declare a cpp executable 88 | add_executable(${PROJECT_NAME} src/ackermann_to_odom_alg.cpp src/ackermann_to_odom_alg_node.cpp) 89 | 90 | # ******************************************************************** 91 | # Add the libraries 92 | # ******************************************************************** 93 | target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES}) 94 | # target_link_libraries(${PROJECT_NAME} ${_LIBRARY}) 95 | 96 | # ******************************************************************** 97 | # Add message headers dependencies 98 | # ******************************************************************** 99 | # add_dependencies(${PROJECT_NAME} _generate_messages_cpp) 100 | # ******************************************************************** 101 | # Add dynamic reconfigure dependencies 102 | # ******************************************************************** 103 | add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS}) 104 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/odomEstimationClass.h: -------------------------------------------------------------------------------- 1 | // Author of Lilo: Edison Velasco 2 | // Email evs25@alu.ua.es 3 | 4 | #ifndef _ODOM_ESTIMATION_CLASS_H_ 5 | #define _ODOM_ESTIMATION_CLASS_H_ 6 | 7 | //std lib 8 | #include 9 | #include 10 | #include 11 | 12 | //PCL 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | // ROS msgs 30 | #include 31 | 32 | //ceres 33 | #include 34 | #include 35 | 36 | //eigen 37 | #include 38 | #include 39 | 40 | //LOCAL LIB 41 | #include 42 | 43 | // STD LIB 44 | #include "STDesc.h" 45 | #include "KDTree_STD.h" 46 | 47 | class OdomEstimationClass 48 | { 49 | 50 | public: 51 | OdomEstimationClass(); 52 | 53 | void init(double edge_resolution,double surf_resolution); 54 | void initMapWithPoints(const pcl::PointCloud::Ptr& edge_in, const pcl::PointCloud::Ptr& surf_in); 55 | void updatePointsToMap(const pcl::PointCloud::Ptr& edge_in, const pcl::PointCloud::Ptr& surf_in, 56 | const std::vector& stdC_pair, const std::vector& stdM_pair, bool clear_map ,double cropBox_len, double cont_opti); 57 | void getMap(pcl::PointCloud::Ptr& laserCloudMap); 58 | 59 | Eigen::Isometry3d odom; 60 | pcl::PointCloud::Ptr laserCloudCornerMap; 61 | pcl::PointCloud::Ptr laserCloudSurfMap; 62 | geometry_msgs::PoseArrayConstPtr std_posesMap; 63 | 64 | pcl::PointCloud::Ptr edge_cloud; 65 | pcl::PointCloud::Ptr surf_cloud; 66 | 67 | private: 68 | 69 | double parameters[8] = {1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; 70 | Eigen::Map> dual_quat = Eigen::Map>(parameters); 71 | 72 | Eigen::Isometry3d last_odom; 73 | 74 | //kd-tree edge 75 | pcl::KdTreeFLANN::Ptr kdtreeEdgeMap; 76 | pcl::KdTreeFLANN::Ptr kdtreeLocalMap; 77 | 78 | //kd-tree surf 79 | pcl::KdTreeFLANN::Ptr kdtreeSurfMap; 80 | 81 | //points downsampling before add to map 82 | pcl::VoxelGrid downSizeFilterEdge; 83 | pcl::VoxelGrid downSizeFilterSurf; 84 | 85 | //local map 86 | pcl::CropBox cropBoxFilter; 87 | 88 | //optimization count 89 | int optimization_count; 90 | 91 | void addPointsToMap(const pcl::PointCloud::Ptr& downsampledEdgeCloud, const pcl::PointCloud::Ptr& downsampledSurfCloud, bool clear_map, double cropBox_len); 92 | void pointAssociateToMap(pcl::PointXYZ const *const pi, pcl::PointXYZ *const po); 93 | void pointLocalToMap(pcl::PointXYZ const *const pi, pcl::PointXYZ *const po); 94 | void downSamplingToMap(const pcl::PointCloud::Ptr& edge_pc_in, pcl::PointCloud::Ptr& edge_pc_out, const pcl::PointCloud::Ptr& surf_pc_in, pcl::PointCloud::Ptr& surf_pc_out); 95 | void occlude_pcd(pcl::PointCloud::Ptr & cld_ptr,int dim, double threshA, double threshB); 96 | void addEdgeDQCostFactor(const pcl::PointCloud::Ptr& pc_in, const pcl::PointCloud::Ptr& map_in, ceres::Problem& problem, ceres::LossFunction *loss_function, ceres::Manifold* dq_manifold, double cropBox_len); 97 | void addSurfDQCostFactor(const pcl::PointCloud::Ptr& pc_in, const pcl::PointCloud::Ptr& map_in, ceres::Problem& problem, ceres::LossFunction *loss_function, ceres::Manifold* dq_manifold, double cropBox_len); 98 | void addSTDCostFactor(std::vector stdC_pair, std::vector stdM_pair, ceres::Problem& problem, ceres::LossFunction *loss_function, ceres::Manifold* dq_manifold); 99 | 100 | }; 101 | 102 | #endif // _ODOM_ESTIMATION_CLASS_H_ -------------------------------------------------------------------------------- /gps_to_odom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(gps_to_odom) 3 | 4 | ## Find catkin macros and libraries 5 | find_package(catkin REQUIRED) 6 | find_package(planning REQUIRED) 7 | find_package(PCL REQUIRED) 8 | FIND_PACKAGE(Eigen3 REQUIRED) 9 | # ******************************************************************** 10 | # Add catkin additional components here 11 | # ******************************************************************** 12 | find_package(catkin REQUIRED COMPONENTS iri_base_algorithm tf eigen_conversions tf_conversions) 13 | 14 | ## System dependencies are found with CMake's conventions 15 | # find_package(Boost REQUIRED COMPONENTS system) 16 | 17 | # ******************************************************************** 18 | # Add system and labrobotica dependencies here 19 | # ******************************************************************** 20 | # find_package( REQUIRED) 21 | 22 | # ******************************************************************** 23 | # Add topic, service and action definition here 24 | # ******************************************************************** 25 | ## Generate messages in the 'msg' folder 26 | # add_message_files( 27 | # FILES 28 | # Message1.msg 29 | # Message2.msg 30 | # ) 31 | 32 | ## Generate services in the 'srv' folder 33 | # add_service_files( 34 | # FILES 35 | # Service1.srv 36 | # Service2.srv 37 | # ) 38 | 39 | ## Generate actions in the 'action' folder 40 | # add_action_files( 41 | # FILES 42 | # Action1.action 43 | # Action2.action 44 | # ) 45 | 46 | ## Generate added messages and services with any dependencies listed here 47 | # generate_messages( 48 | # DEPENDENCIES 49 | # std_msgs # Or other packages containing msgs 50 | # ) 51 | 52 | # ******************************************************************** 53 | # Add the dynamic reconfigure file 54 | # ******************************************************************** 55 | generate_dynamic_reconfigure_options(cfg/GpsToOdom.cfg) 56 | 57 | # ******************************************************************** 58 | # Add run time dependencies here 59 | # ******************************************************************** 60 | catkin_package( 61 | # INCLUDE_DIRS 62 | # LIBRARIES 63 | # ******************************************************************** 64 | # Add ROS and IRI ROS run time dependencies 65 | # ******************************************************************** 66 | CATKIN_DEPENDS iri_base_algorithm 67 | # ******************************************************************** 68 | # Add system and labrobotica run time dependencies here 69 | # ******************************************************************** 70 | DEPENDS Eigen 71 | ) 72 | 73 | ########### 74 | ## Build ## 75 | ########### 76 | 77 | # ******************************************************************** 78 | # Add the include directories 79 | # ******************************************************************** 80 | include_directories(include) 81 | include_directories(${catkin_INCLUDE_DIRS} 82 | ${PCL_INCLUDE_DIRS} 83 | ${EIGEN_INCLUDE_DIRS}) 84 | # include_directories(${_INCLUDE_DIR}) 85 | 86 | ## Declare a cpp library 87 | # add_library(${PROJECT_NAME} ) 88 | 89 | ## Declare a cpp executable 90 | add_executable(${PROJECT_NAME} src/gps_to_odom_alg.cpp src/gps_to_odom_alg_node.cpp) 91 | 92 | # ******************************************************************** 93 | # Add the libraries 94 | # ******************************************************************** 95 | target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES}) 96 | TARGET_LINK_LIBRARIES(${PROJECT_NAME} planning) 97 | # target_link_libraries(${PROJECT_NAME} ${_LIBRARY}) 98 | 99 | # ******************************************************************** 100 | # Add message headers dependencies 101 | # ******************************************************************** 102 | # add_dependencies(${PROJECT_NAME} _generate_messages_cpp) 103 | # ******************************************************************** 104 | # Add dynamic reconfigure dependencies 105 | # ******************************************************************** 106 | add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS}) 107 | -------------------------------------------------------------------------------- /ackermann_to_odom/src/ackermann_to_odom_alg_node.cpp: -------------------------------------------------------------------------------- 1 | #include "ackermann_to_odom_alg_node.h" 2 | 3 | AckermannToOdomAlgNode::AckermannToOdomAlgNode(void) : 4 | algorithm_base::IriBaseAlgorithm() 5 | { 6 | //init class attributes if necessary 7 | //this->loop_rate_ = 10; //in [Hz] 8 | this->virtual_imu_msg_.orientation.x = 0.0; 9 | this->virtual_imu_msg_.orientation.y = 0.0; 10 | this->virtual_imu_msg_.orientation.z = 0.0; 11 | this->virtual_imu_msg_.orientation.w = 1.0; 12 | this->estimated_ackermann_state_.drive.speed = 0.0; 13 | this->estimated_ackermann_state_.drive.steering_angle = 0.0; 14 | 15 | // [init publishers] 16 | this->odometry_publisher_ = this->public_node_handle_.advertise < nav_msgs::Odometry > ("/odometry", 1); 17 | this->pose_publisher_ = this->public_node_handle_.advertise < geometry_msgs::PoseWithCovarianceStamped > ("/odometry_pose", 1); 18 | 19 | // [init subscribers] 20 | this->estimated_ackermann_subscriber_ = this->public_node_handle_.subscribe( 21 | "/estimated_ackermann_state", 1, &AckermannToOdomAlgNode::cb_ackermannState, this); 22 | this->virtual_imu_subscriber_ = this->public_node_handle_.subscribe("/virtual_imu_data", 1, 23 | &AckermannToOdomAlgNode::cb_imuData, this); 24 | 25 | // [init services] 26 | 27 | // [init clients] 28 | 29 | // [init action servers] 30 | 31 | // [init action clients] 32 | } 33 | 34 | AckermannToOdomAlgNode::~AckermannToOdomAlgNode(void) 35 | { 36 | // [free dynamic memory] 37 | } 38 | 39 | void AckermannToOdomAlgNode::mainNodeThread(void) 40 | { 41 | static bool first_exec = true; 42 | static bool odom_in_tf; 43 | static bool scan_in_tf; 44 | static std::string frame_id; 45 | static std::string child_id; 46 | 47 | // [read parameters] 48 | if (first_exec) 49 | { 50 | this->public_node_handle_.getParam("/odom_in_tf", odom_in_tf); 51 | this->public_node_handle_.getParam("/scan_in_tf", scan_in_tf); 52 | this->public_node_handle_.getParam("/frame_id", frame_id); 53 | this->public_node_handle_.getParam("/child_id", child_id); 54 | first_exec = false; 55 | } 56 | 57 | // [listen transform] 58 | try 59 | { 60 | this->listener_.lookupTransform(frame_id, child_id, ros::Time(0), this->scan_trans_); 61 | } 62 | catch (tf::TransformException ex) 63 | { 64 | ROS_ERROR("%s", ex.what()); 65 | ros::Duration(1.0).sleep(); 66 | } 67 | 68 | // [fill msg structures] 69 | this->alg_.generateNewOdometryMsg2D(this->estimated_ackermann_state_, this->virtual_imu_msg_, this->odometry_pose_, 70 | this->odometry_, this->odom_trans_); 71 | 72 | // [fill srv structure and make request to the server] 73 | 74 | // [fill action structure and make request to the action server] 75 | 76 | // [publish messages] 77 | if (odom_in_tf) 78 | { 79 | this->broadcaster_.sendTransform(this->odom_trans_); 80 | } 81 | if (scan_in_tf) 82 | { 83 | this->broadcaster_.sendTransform(this->scan_trans_); 84 | } 85 | 86 | this->odometry_publisher_.publish(this->odometry_); 87 | this->pose_publisher_.publish(this->odometry_pose_); 88 | } 89 | 90 | /* [subscriber callbacks] */ 91 | void AckermannToOdomAlgNode::cb_ackermannState( 92 | const ackermann_msgs::AckermannDriveStamped::ConstPtr& estimated_ackermann_state_msg) 93 | { 94 | this->alg_.lock(); 95 | 96 | this->estimated_ackermann_state_.drive.speed = estimated_ackermann_state_msg->drive.speed; 97 | this->estimated_ackermann_state_.drive.steering_angle = estimated_ackermann_state_msg->drive.steering_angle; 98 | 99 | this->alg_.unlock(); 100 | } 101 | 102 | void AckermannToOdomAlgNode::cb_imuData(const sensor_msgs::Imu::ConstPtr& Imu_msg) 103 | { 104 | this->alg_.lock(); 105 | 106 | this->virtual_imu_msg_.orientation.x = Imu_msg->orientation.x; 107 | this->virtual_imu_msg_.orientation.y = Imu_msg->orientation.y; 108 | this->virtual_imu_msg_.orientation.z = Imu_msg->orientation.z; 109 | this->virtual_imu_msg_.orientation.w = Imu_msg->orientation.w; 110 | 111 | this->alg_.unlock(); 112 | } 113 | 114 | /* [service callbacks] */ 115 | 116 | /* [action callbacks] */ 117 | 118 | /* [action requests] */ 119 | 120 | void AckermannToOdomAlgNode::node_config_update(Config &config, uint32_t level) 121 | { 122 | this->alg_.lock(); 123 | this->config_ = config; 124 | this->alg_.unlock(); 125 | } 126 | 127 | void AckermannToOdomAlgNode::addNodeDiagnostics(void) 128 | { 129 | } 130 | 131 | /* main function */ 132 | int main(int argc, char *argv[]) 133 | { 134 | return algorithm_base::main < AckermannToOdomAlgNode > (argc, argv, "ackermann_to_odom_alg_node"); 135 | } 136 | -------------------------------------------------------------------------------- /gps_to_odom/include/gps_to_odom_alg.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010-2011 Institut de Robotica i Informatica Industrial, CSIC-UPC. 2 | // Author 3 | // All rights reserved. 4 | // 5 | // This file is part of iri-ros-pkg 6 | // iri-ros-pkg is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU Lesser General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU Lesser General Public License 17 | // along with this program. If not, see . 18 | // 19 | // IMPORTANT NOTE: This code has been generated through a script from the 20 | // iri_ros_scripts. Please do NOT delete any comments to guarantee the correctness 21 | // of the scripts. ROS topics can be easly add by using those scripts. Please 22 | // refer to the IRI wiki page for more information: 23 | // http://wikiri.upc.es/index.php/Robotics_Lab 24 | /** 25 | * \file gps_to_odom_alg.h 26 | * 27 | * Created on: 04 Dec 2018 28 | * Author: m.a.munoz 29 | */ 30 | 31 | #ifndef _gps_to_odom_alg_h_ 32 | #define _gps_to_odom_alg_h_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include "nav_msgs/Odometry.h" 38 | #include "sensor_msgs/NavSatFix.h" 39 | #include "geometry_msgs/TwistWithCovarianceStamped.h" 40 | #include "geometry_msgs/TwistStamped.h" 41 | #include "geometry_msgs/Vector3Stamped.h" 42 | #include "math.h" 43 | #include "planning/graph.h" 44 | 45 | //include gps_to_odom_alg main library 46 | 47 | /** 48 | * \brief IRI ROS Specific Driver Class 49 | * 50 | * 51 | */ 52 | class GpsToOdomAlgorithm 53 | { 54 | protected: 55 | /** 56 | * \brief define config type 57 | * 58 | * Define a Config type with the GpsToOdomConfig. All driver implementations 59 | * will then use the same variable type Config. 60 | */ 61 | pthread_mutex_t access_; 62 | 63 | // private attributes and methods 64 | 65 | public: 66 | /** 67 | * \brief define config type 68 | * 69 | * Define a Config type with the GpsToOdomConfig. All driver implementations 70 | * will then use the same variable type Config. 71 | */ 72 | typedef gps_to_odom::GpsToOdomConfig Config; 73 | 74 | /** 75 | * \brief config variable 76 | * 77 | * This variable has all the driver parameters defined in the cfg config file. 78 | * Is updated everytime function config_update() is called. 79 | */ 80 | Config config_; 81 | 82 | /** 83 | * \brief constructor 84 | * 85 | * In this constructor parameters related to the specific driver can be 86 | * initalized. Those parameters can be also set in the openDriver() function. 87 | * Attributes from the main node driver class IriBaseDriver such as loop_rate, 88 | * may be also overload here. 89 | */ 90 | GpsToOdomAlgorithm(void); 91 | 92 | /** 93 | * \brief Lock Algorithm 94 | * 95 | * Locks access to the Algorithm class 96 | */ 97 | void lock(void) { pthread_mutex_lock(&this->access_); }; 98 | 99 | /** 100 | * \brief Unlock Algorithm 101 | * 102 | * Unlocks access to the Algorithm class 103 | */ 104 | void unlock(void) { pthread_mutex_unlock(&this->access_); }; 105 | 106 | /** 107 | * \brief Tries Access to Algorithm 108 | * 109 | * Tries access to Algorithm 110 | * 111 | * \return true if the lock was adquired, false otherwise 112 | */ 113 | bool try_enter(void) 114 | { 115 | if(pthread_mutex_trylock(&this->access_)==0) 116 | return true; 117 | else 118 | return false; 119 | }; 120 | 121 | /** 122 | * \brief config update 123 | * 124 | * In this function the driver parameters must be updated with the input 125 | * config variable. Then the new configuration state will be stored in the 126 | * Config attribute. 127 | * 128 | * \param new_cfg the new driver configuration state 129 | * 130 | * \param level level in which the update is taken place 131 | */ 132 | void config_update(Config& config, uint32_t level=0); 133 | 134 | // here define all gps_to_odom_alg interface methods to retrieve and set 135 | // the driver parameters 136 | 137 | /** 138 | * \brief Destructor 139 | * 140 | * This destructor is called when the object is about to be destroyed. 141 | * 142 | */ 143 | ~GpsToOdomAlgorithm(void); 144 | }; 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /dualquat_LOAM/src/laserMappingNode.cpp: -------------------------------------------------------------------------------- 1 | // The mapping process is based on the FLOAM code. 2 | // Author of FLOAM: Wang Han 3 | // Email wh200720041@gmail.com 4 | // Author of LiDAR-Odometry_DQ: Edison Velasco 5 | // Email edison.velasco@ua.es 6 | 7 | //c++ lib 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | //ros lib 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | //pcl lib 23 | #include 24 | #include 25 | #include 26 | 27 | #include "laserMappingClass.h" 28 | 29 | 30 | LaserMappingClass laserMapping; 31 | std::mutex mutex_lock; 32 | std::queue odometryBuf; 33 | std::queue pointCloudBuf; 34 | float scan_period = 0.1; // time in seconds 35 | 36 | ros::Publisher map_pub; 37 | void odomCallback(const nav_msgs::Odometry::ConstPtr &msg) 38 | { 39 | mutex_lock.lock(); 40 | odometryBuf.push(msg); 41 | mutex_lock.unlock(); 42 | } 43 | 44 | void velodyneHandler(const sensor_msgs::PointCloud2ConstPtr &laserCloudMsg) 45 | { 46 | mutex_lock.lock(); 47 | pointCloudBuf.push(laserCloudMsg); 48 | mutex_lock.unlock(); 49 | } 50 | 51 | 52 | void laser_mapping(){ 53 | while(1){ 54 | if(!odometryBuf.empty() && !pointCloudBuf.empty()){ 55 | 56 | //read data 57 | mutex_lock.lock(); 58 | if(!pointCloudBuf.empty() && pointCloudBuf.front()->header.stamp.toSec()header.stamp.toSec()-0.5*scan_period){ 59 | ROS_INFO("time stamp unaligned error and pointcloud discarded, pls check your data --> laser mapping node"); 60 | pointCloudBuf.pop(); 61 | mutex_lock.unlock(); 62 | continue; 63 | } 64 | 65 | if(!odometryBuf.empty() && odometryBuf.front()->header.stamp.toSec() < pointCloudBuf.front()->header.stamp.toSec()-0.5*scan_period){ 66 | odometryBuf.pop(); 67 | ROS_INFO("time stamp unaligned with path final, pls check your data --> laser mapping node"); 68 | mutex_lock.unlock(); 69 | continue; 70 | } 71 | 72 | //if time aligned 73 | pcl::PointCloud::Ptr pointcloud_in(new pcl::PointCloud()); 74 | pcl::fromROSMsg(*pointCloudBuf.front(), *pointcloud_in); 75 | ros::Time pointcloud_time = (pointCloudBuf.front())->header.stamp; 76 | 77 | Eigen::Isometry3d current_pose = Eigen::Isometry3d::Identity(); 78 | current_pose.rotate(Eigen::Quaterniond(odometryBuf.front()->pose.pose.orientation.w,odometryBuf.front()->pose.pose.orientation.x,odometryBuf.front()->pose.pose.orientation.y,odometryBuf.front()->pose.pose.orientation.z)); 79 | current_pose.pretranslate(Eigen::Vector3d(odometryBuf.front()->pose.pose.position.x,odometryBuf.front()->pose.pose.position.y,odometryBuf.front()->pose.pose.position.z)); 80 | pointCloudBuf.pop(); 81 | odometryBuf.pop(); 82 | mutex_lock.unlock(); 83 | 84 | laserMapping.updateCurrentPointsToMap(pointcloud_in,current_pose); 85 | 86 | pcl::PointCloud::Ptr pc_map = laserMapping.getMap(); 87 | sensor_msgs::PointCloud2 PointsMsg; 88 | pcl::toROSMsg(*pc_map, PointsMsg); 89 | PointsMsg.header.stamp = pointcloud_time; 90 | PointsMsg.header.frame_id = "map"; 91 | map_pub.publish(PointsMsg); 92 | 93 | } 94 | //sleep 2 ms every time 95 | std::chrono::milliseconds dura(2); 96 | std::this_thread::sleep_for(dura); 97 | } 98 | } 99 | 100 | int main(int argc, char **argv) 101 | { 102 | ros::init(argc, argv, "main"); 103 | ros::NodeHandle nh; 104 | 105 | double scan_period= 0.5; 106 | double max_dis = 100.0; 107 | double min_dis = 2.0; 108 | double map_resolution = 0.2; 109 | 110 | nh.getParam("/scan_period", scan_period); 111 | nh.getParam("/max_dis", max_dis); 112 | nh.getParam("/min_dis", min_dis); 113 | nh.getParam("/map_resolution", map_resolution); 114 | 115 | laserMapping.init(map_resolution); 116 | ros::Subscriber subLaserCloud = nh.subscribe("/ouster/points", 100, velodyneHandler); 117 | ros::Subscriber subOdometry = nh.subscribe("/odom_dq", 100, odomCallback); 118 | 119 | map_pub = nh.advertise("/map", 100); 120 | std::thread laser_mapping_process{laser_mapping}; 121 | 122 | ros::spin(); 123 | 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /dualquat_LOAM/include/dualquat/dualquat_base.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dualquat/dualquat_base.h 3 | */ 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace dualquat 10 | { 11 | 12 | template 13 | class DualQuaternion; 14 | 15 | using DualQuaternionf = DualQuaternion; 16 | using DualQuaterniond = DualQuaternion; 17 | 18 | template 19 | using Vector3 = Eigen::Matrix; 20 | 21 | template 22 | using Quaternion = Eigen::Quaternion; 23 | 24 | template 25 | class DualQuaternion 26 | { 27 | static_assert(std::is_floating_point::value, 28 | "Template parameter T must be floating_point type."); 29 | public: 30 | using value_type = T; 31 | 32 | /* Constructors */ 33 | DualQuaternion() 34 | {} 35 | 36 | DualQuaternion( 37 | const Quaternion& real, 38 | const Quaternion& dual) 39 | : real_(real), 40 | dual_(dual) 41 | {} 42 | 43 | /** 44 | * Creates a new dual quaternion with the given vector. 45 | */ 46 | explicit DualQuaternion(const Vector3& v) 47 | : DualQuaternion( 48 | Quaternion::Identity(), 49 | Quaternion(T(0), v.x(), v.y(), v.z())) 50 | {} 51 | 52 | /** 53 | * Creates a new dual quaternion with the given line (in Plucker coordinates). 54 | */ 55 | DualQuaternion(const Vector3& l, const Vector3& m) 56 | : DualQuaternion( 57 | Quaternion(T(0), l.x(), l.y(), l.z()), 58 | Quaternion(T(0), m.x(), m.y(), m.z())) 59 | {} 60 | 61 | /* Accessors */ 62 | const Quaternion& real() const noexcept { return real_; } 63 | const Quaternion& dual() const noexcept { return dual_; } 64 | 65 | Quaternion& real() noexcept { return real_; } 66 | Quaternion& dual() noexcept { return dual_; } 67 | 68 | /* Assignment operators */ 69 | DualQuaternion& operator += (const DualQuaternion&); 70 | DualQuaternion& operator -= (const DualQuaternion&); 71 | DualQuaternion& operator *= (const DualQuaternion&); 72 | DualQuaternion& operator *= (T); 73 | 74 | private: 75 | static constexpr bool needs_to_align = (sizeof(Quaternion) % 16) == 0; 76 | 77 | public: 78 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(needs_to_align) 79 | 80 | private: 81 | Quaternion real_; 82 | Quaternion dual_; 83 | }; 84 | 85 | /* Assignment operators */ 86 | 87 | template 88 | DualQuaternion& 89 | DualQuaternion::operator += (const DualQuaternion& rhs) 90 | { 91 | real_ = real_.coeffs() + rhs.real().coeffs(); 92 | dual_ = dual_.coeffs() + rhs.dual().coeffs(); 93 | return *this; 94 | } 95 | 96 | template 97 | DualQuaternion& 98 | DualQuaternion::operator -= (const DualQuaternion& rhs) 99 | { 100 | real_ = real_.coeffs() - rhs.real().coeffs(); 101 | dual_ = dual_.coeffs() - rhs.dual().coeffs(); 102 | return *this; 103 | } 104 | 105 | template 106 | DualQuaternion& 107 | DualQuaternion::operator *= (const DualQuaternion& rhs) 108 | { 109 | auto temp = real_; 110 | real_ = temp * rhs.real(); 111 | dual_ = (temp * rhs.dual()).coeffs() + (dual_ * rhs.real()).coeffs(); 112 | return *this; 113 | } 114 | 115 | template 116 | DualQuaternion& 117 | DualQuaternion::operator *= (T rhs) 118 | { 119 | real_.coeffs() *= rhs; 120 | dual_.coeffs() *= rhs; 121 | return *this; 122 | } 123 | 124 | /* Unary operators */ 125 | 126 | template 127 | DualQuaternion 128 | operator + (const DualQuaternion& rhs) 129 | { 130 | return rhs; 131 | } 132 | 133 | template 134 | DualQuaternion 135 | operator - (const DualQuaternion& rhs) 136 | { 137 | DualQuaternion temp; 138 | temp.real() = -rhs.real().coeffs(); 139 | temp.dual() = -rhs.dual().coeffs(); 140 | return temp; 141 | } 142 | 143 | /* Binary operators */ 144 | 145 | template 146 | DualQuaternion 147 | operator + (const DualQuaternion& lhs, const DualQuaternion& rhs) 148 | { 149 | DualQuaternion temp(lhs); 150 | return temp += rhs; 151 | } 152 | 153 | template 154 | DualQuaternion 155 | operator - (const DualQuaternion& lhs, const DualQuaternion& rhs) 156 | { 157 | DualQuaternion temp(lhs); 158 | return temp -= rhs; 159 | } 160 | 161 | template 162 | DualQuaternion 163 | operator * (const DualQuaternion& lhs, const DualQuaternion& rhs) 164 | { 165 | DualQuaternion temp(lhs); 166 | return temp *= rhs; 167 | } 168 | 169 | template 170 | DualQuaternion 171 | operator * (const DualQuaternion& lhs, T rhs) 172 | { 173 | DualQuaternion temp(lhs); 174 | return temp *= rhs; 175 | } 176 | 177 | template 178 | DualQuaternion 179 | operator * (T lhs, const DualQuaternion& rhs) 180 | { 181 | DualQuaternion temp(rhs); 182 | return temp *= lhs; 183 | } 184 | 185 | } // namespace dualquat 186 | -------------------------------------------------------------------------------- /dualquat_LOAM/README.md: -------------------------------------------------------------------------------- 1 | 2 | # LiDAR Odometry with Dual Quaternion Optimization 3 | 4 | This repository contains an approach for LiDAR odometry based on edge and surface features, as well as Stable Triangle Descriptors (STD). These features are optimized using Dual Quaternion (DQ) optimization. 5 | 6 | This method introduces a novel approach for LiDAR odometry estimation, fully parameterized with dual quaternions. The features derived from the point cloud, including edges, surfaces, and Stable Triangle Descriptors (STD), along with the optimization process, are all expressed in the dual quaternion space. This enables a direct combination of translation and orientation errors using dual quaternion operations, significantly improving pose estimation accuracy. Comparative experiments against other state-of-the-art methods show that this approach achieves enhanced performance. 7 | 8 | An overview of our LiDAR-Only odometry method can be found in [DualQuat_LOAM](https://aurova-projects.github.io/dualquat_loam/) of AUROVA PROJECTS 9 | 10 | ## Docker is all you need 11 | 12 | You can also use only Docker to run DualQuat-LOAM. To do so, follow these simple steps. 13 | 14 | ### Clone the repository 15 | 16 | ```bash 17 | git clone https://github.com/AUROVA-LAB/aurova_odom.git 18 | ``` 19 | 20 | ### Build the Docker image 21 | 22 | ```bash 23 | cd /path/to/your/directory/aurova_odom/dualquat_LOAM/ 24 | sudo docker build -t dualquat_loam . 25 | ``` 26 | 27 | ### Run the container 28 | 29 | ```bash 30 | sudo docker run --shm-size=1g \ 31 | --privileged \ 32 | --ulimit memlock=-1 \ 33 | --ulimit stack=67108864 \ 34 | --rm -it --net=host -e DISPLAY=:0 \ 35 | --user=root \ 36 | -v /tmp/.X11-unix:/tmp/.X11-unix:rw \ 37 | --name dualquatloam_container \ 38 | --gpus all \ 39 | --cpuset-cpus=0-3 \ 40 | dualquat_loam 41 | ``` 42 | 43 | ### Inside the container 44 | 45 | You will need at least two terminals. 46 | 47 | In one terminal, run the odometry estimation node: 48 | 49 | ```bash 50 | source devel/setup.bash 51 | roslaunch dualquat_loam odomEstimation_KITTI_display_STD.launch 52 | ``` 53 | 54 | In the second terminal, run the feature extraction: 55 | 56 | ```bash 57 | source devel/setup.bash 58 | roslaunch pc_feature_extraction Kitti_extraction.launch 59 | ``` 60 | 61 | Now you can test the pose estimation with our dualquat-loam using the [KITTI](https://www.cvlibs.net/datasets/kitti/raw_data.php) dataset. 62 | 63 | ### Note (outside the container): 64 | 65 | If you need to display any graphical interface started inside the container, first run this outside the container: 66 | 67 | ```bash 68 | xhost +local: 69 | ``` 70 | 71 | ## Requirements (without Docker) 72 | 73 | - **ROS 1** (tested in ROS-Noetic) 74 | - **PCL (Point Cloud Library)** 75 | - **Eigen** for linear algebra operations 76 | - **[Ceres Solver](http://ceres-solver.org/)** (tested with 2.2.0 library version) 77 | - **[Nanoflann library](https://github.com/jlblancoc/nanoflann)** 78 | 79 | ### Nanoflann install Instructions: 80 | ```bash 81 | git clone https://github.com/jlblancoc/nanoflann.git ~/your-directory/nanoflann 82 | cd ~/your-directory/nanoflann 83 | mkdir build 84 | cd build 85 | cmake .. 86 | sudo make install 87 | ``` 88 | 89 | - Point cloud preprocessing node ([aurova_preprocessed](https://github.com/AUROVA-LAB/aurova_preprocessed)). More specifically [pc_feature](https://github.com/AUROVA-LAB/aurova_preprocessed/tree/master/pc_features) node. 90 | 91 | And also it is necessary the dependencies of the [STD]((https://github.com/hku-mars/STD)) descriptors: 92 | 93 | ```bash 94 | sudo add-apt-repository ppa:borglab/gtsam-release-4.0 95 | sudo apt update 96 | sudo apt install -y libgtsam-dev libgtsam-unstable-dev 97 | ``` 98 | ## Installation (without Docker) 99 | 100 | ### 1. Clone the repository 101 | 102 | ```bash 103 | cd ~/catkin_ws/src 104 | git clone https://github.com/AUROVA-LAB/aurova_odom.git 105 | 106 | ``` 107 | 108 | ### 2. Build the package 109 | 110 | Navigate to your catkin workspace and build the package: 111 | 112 | ```bash 113 | cd ~/catkin_ws 114 | catkin_make --only-pkg-with-deps dualquat_loam 115 | ``` 116 | 117 | ## Usage 118 | 119 | ### 1. Launch the pc_feature node 120 | 121 | We have separated the point cloud preprocessing for edge and surface feature extraction, allowing the user to implement this package with their own code or use the one provided in [pc_feature](https://github.com/AUROVA-LAB/aurova_preprocessed/tree/master/pc_features) node. 122 | 123 | ```bash 124 | roslaunch pc_feature_extraction Kitti_extraction.launch 125 | ``` 126 | 127 | ### 2. Launch the odometry node 128 | 129 | The package has been tested with the [KITTI](https://www.cvlibs.net/datasets/kitti/raw_data.php) (00 - 010 sequences), [HeliPR](https://sites.google.com/view/heliprdataset) (Roundabout02, Bridge02, Town03), [conSLAM](https://github.com/mac137/ConSLAM/tree/main) (sequence02) and [NTU-VIRAL](https://ntu-aris.github.io/ntu_viral_dataset/)(eee03) datasets. 130 | 131 | ```bash 132 | roslaunch dualquat_loam odomEstimation_KITTI_dataset.launch 133 | ``` 134 | Make sure the parameters and topics are correctly set according to your LiDAR sensor and point cloud input. 135 | 136 | ## Acknowledgements 137 | 138 | We would like to acknowledge the following repositories for their contributions to this project: 139 | 140 | - [F-LOAM](https://github.com/wh200720041/floam) 141 | - [STD Descriptors](https://github.com/hku-mars/STD) 142 | - [DQ Robotics](https://github.com/dqrobotics) 143 | - [Nanoflann](https://github.com/jlblancoc/nanoflann) 144 | -------------------------------------------------------------------------------- /odom_estimation_pc/src/lidarOptimization.cpp: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | // Author of Lilo: Edison Velasco 6 | // Email evs25@alu.ua.es 7 | 8 | #include "lidarOptimization.h" 9 | 10 | EdgeAnalyticCostFunction::EdgeAnalyticCostFunction(Eigen::Vector3d curr_point_, Eigen::Vector3d last_point_a_, Eigen::Vector3d last_point_b_) 11 | : curr_point(curr_point_), last_point_a(last_point_a_), last_point_b(last_point_b_){ 12 | 13 | } 14 | 15 | bool EdgeAnalyticCostFunction::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const 16 | { 17 | 18 | Eigen::Map q_last_curr(parameters[0]); 19 | Eigen::Map t_last_curr(parameters[0] + 4); 20 | Eigen::Vector3d lp; 21 | lp = q_last_curr * curr_point + t_last_curr; 22 | 23 | Eigen::Vector3d nu = (lp - last_point_a).cross(lp - last_point_b); 24 | Eigen::Vector3d de = last_point_a - last_point_b; 25 | double de_norm = de.norm(); 26 | residuals[0] = nu.norm()/de_norm; 27 | 28 | if(jacobians != NULL) 29 | { 30 | if(jacobians[0] != NULL) 31 | { 32 | Eigen::Matrix3d skew_lp = skew(lp); 33 | Eigen::Matrix dp_by_se3; 34 | dp_by_se3.block<3,3>(0,0) = -skew_lp; 35 | (dp_by_se3.block<3,3>(0, 3)).setIdentity(); 36 | Eigen::Map > J_se3(jacobians[0]); 37 | J_se3.setZero(); 38 | Eigen::Matrix3d skew_de = skew(de); 39 | J_se3.block<1,6>(0,0) = - nu.transpose() / nu.norm() * skew_de * dp_by_se3/de_norm; 40 | 41 | } 42 | } 43 | 44 | return true; 45 | 46 | } 47 | 48 | 49 | SurfNormAnalyticCostFunction::SurfNormAnalyticCostFunction(Eigen::Vector3d curr_point_, Eigen::Vector3d plane_unit_norm_, double negative_OA_dot_norm_) 50 | : curr_point(curr_point_), plane_unit_norm(plane_unit_norm_), negative_OA_dot_norm(negative_OA_dot_norm_){ 51 | 52 | } 53 | 54 | bool SurfNormAnalyticCostFunction::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const 55 | { 56 | Eigen::Map q_w_curr(parameters[0]); 57 | Eigen::Map t_w_curr(parameters[0] + 4); 58 | Eigen::Vector3d point_w = q_w_curr * curr_point + t_w_curr; 59 | residuals[0] = plane_unit_norm.dot(point_w) + negative_OA_dot_norm; 60 | 61 | if(jacobians != NULL) 62 | { 63 | if(jacobians[0] != NULL) 64 | { 65 | Eigen::Matrix3d skew_point_w = skew(point_w); 66 | Eigen::Matrix dp_by_se3; 67 | dp_by_se3.block<3,3>(0,0) = -skew_point_w; 68 | (dp_by_se3.block<3,3>(0, 3)).setIdentity(); 69 | Eigen::Map > J_se3(jacobians[0]); 70 | J_se3.setZero(); 71 | J_se3.block<1,6>(0,0) = plane_unit_norm.transpose() * dp_by_se3; 72 | 73 | } 74 | } 75 | return true; 76 | 77 | } 78 | 79 | 80 | bool PoseSE3Parameterization::Plus(const double *x, const double *delta, double *x_plus_delta) const 81 | { 82 | Eigen::Map trans(x + 4); 83 | 84 | Eigen::Quaterniond delta_q; 85 | Eigen::Vector3d delta_t; 86 | getTransformFromSe3(Eigen::Map>(delta), delta_q, delta_t); 87 | Eigen::Map quater(x); 88 | Eigen::Map quater_plus(x_plus_delta); 89 | Eigen::Map trans_plus(x_plus_delta + 4); 90 | 91 | quater_plus = delta_q * quater; 92 | trans_plus = delta_q * trans + delta_t; 93 | 94 | return true; 95 | } 96 | 97 | bool PoseSE3Parameterization::ComputeJacobian(const double *x, double *jacobian) const 98 | { 99 | Eigen::Map> j(jacobian); 100 | (j.topRows(6)).setIdentity(); 101 | (j.bottomRows(1)).setZero(); 102 | 103 | return true; 104 | } 105 | 106 | void getTransformFromSe3(const Eigen::Matrix& se3, Eigen::Quaterniond& q, Eigen::Vector3d& t){ 107 | Eigen::Vector3d omega(se3.data()); 108 | Eigen::Vector3d upsilon(se3.data()+3); 109 | Eigen::Matrix3d Omega = skew(omega); 110 | 111 | double theta = omega.norm(); 112 | double half_theta = 0.5*theta; 113 | 114 | double imag_factor; 115 | double real_factor = cos(half_theta); 116 | if(theta<1e-10) 117 | { 118 | double theta_sq = theta*theta; 119 | double theta_po4 = theta_sq*theta_sq; 120 | imag_factor = 0.5-0.0208333*theta_sq+0.000260417*theta_po4; 121 | } 122 | else 123 | { 124 | double sin_half_theta = sin(half_theta); 125 | imag_factor = sin_half_theta/theta; 126 | } 127 | 128 | q = Eigen::Quaterniond(real_factor, imag_factor*omega.x(), imag_factor*omega.y(), imag_factor*omega.z()); 129 | 130 | 131 | Eigen::Matrix3d J; 132 | if (theta<1e-10) 133 | { 134 | J = q.matrix(); 135 | } 136 | else 137 | { 138 | Eigen::Matrix3d Omega2 = Omega*Omega; 139 | J = (Eigen::Matrix3d::Identity() + (1-cos(theta))/(theta*theta)*Omega + (theta-sin(theta))/(pow(theta,3))*Omega2); 140 | } 141 | 142 | t = J*upsilon; 143 | } 144 | 145 | Eigen::Matrix skew(Eigen::Matrix& mat_in){ 146 | Eigen::Matrix skew_mat; 147 | skew_mat.setZero(); 148 | skew_mat(0,1) = -mat_in(2); 149 | skew_mat(0,2) = mat_in(1); 150 | skew_mat(1,2) = -mat_in(0); 151 | skew_mat(1,0) = mat_in(2); 152 | skew_mat(2,0) = -mat_in(1); 153 | skew_mat(2,1) = mat_in(0); 154 | return skew_mat; 155 | } 156 | -------------------------------------------------------------------------------- /ackermann_to_odom/include/ackermann_to_odom_alg.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010-2011 Institut de Robotica i Informatica Industrial, CSIC-UPC. 2 | // Author 3 | // All rights reserved. 4 | // 5 | // This file is part of iri-ros-pkg 6 | // iri-ros-pkg is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU Lesser General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU Lesser General Public License 17 | // along with this program. If not, see . 18 | // 19 | // IMPORTANT NOTE: This code has been generated through a script from the 20 | // iri_ros_scripts. Please do NOT delete any comments to guarantee the correctness 21 | // of the scripts. ROS topics can be easly add by using those scripts. Please 22 | // refer to the IRI wiki page for more information: 23 | // http://wikiri.upc.es/index.php/Robotics_Lab 24 | /** 25 | * \file ackermann_to_odom_alg.h 26 | * 27 | * Created on: 04 Sep 2018 28 | * Author: m.a.munoz 29 | */ 30 | 31 | #ifndef _ackermann_to_odom_alg_h_ 32 | #define _ackermann_to_odom_alg_h_ 33 | 34 | #include 35 | #include "ackermann_to_odom_alg.h" 36 | #include "ackermann_msgs/AckermannDriveStamped.h" 37 | #include "geometry_msgs/PoseWithCovarianceStamped.h" 38 | #include "nav_msgs/Odometry.h" 39 | #include "sensor_msgs/Imu.h" 40 | #include 41 | 42 | #define MAX_DIFF 1.5 43 | 44 | //include ackermann_to_odom_alg main library 45 | 46 | /** 47 | * \brief IRI ROS Specific Driver Class 48 | * 49 | * This class implements the main algorithm that performs the package. 50 | */ 51 | class AckermannToOdomAlgorithm 52 | { 53 | protected: 54 | /** 55 | * \brief define config type 56 | * 57 | * Define a Config type with the AckermannToOdomConfig. All driver implementations 58 | * will then use the same variable type Config. 59 | */ 60 | pthread_mutex_t access_; 61 | 62 | // private attributes and methods 63 | 64 | public: 65 | /** 66 | * \brief define config type 67 | * 68 | * Define a Config type with the AckermannToOdomConfig. All driver implementations 69 | * will then use the same variable type Config. 70 | */ 71 | typedef ackermann_to_odom::AckermannToOdomConfig Config; 72 | 73 | /** 74 | * \brief config variable 75 | * 76 | * This variable has all the driver parameters defined in the cfg config file. 77 | * Is updated everytime function config_update() is called. 78 | */ 79 | Config config_; 80 | 81 | /** 82 | * \brief constructor 83 | * 84 | * In this constructor parameters related to the specific driver can be 85 | * initalized. Those parameters can be also set in the openDriver() function. 86 | * Attributes from the main node driver class IriBaseDriver such as loop_rate, 87 | * may be also overload here. 88 | */ 89 | AckermannToOdomAlgorithm(void); 90 | 91 | /** 92 | * \brief Lock Algorithm 93 | * 94 | * Locks access to the Algorithm class 95 | */ 96 | void lock(void) 97 | { 98 | pthread_mutex_lock(&this->access_); 99 | } 100 | ; 101 | 102 | /** 103 | * \brief Unlock Algorithm 104 | * 105 | * Unlocks access to the Algorithm class 106 | */ 107 | void unlock(void) 108 | { 109 | pthread_mutex_unlock(&this->access_); 110 | } 111 | ; 112 | 113 | /** 114 | * \brief Tries Access to Algorithm 115 | * 116 | * Tries access to Algorithm 117 | * 118 | * \return true if the lock was adquired, false otherwise 119 | */ 120 | bool try_enter(void) 121 | { 122 | if (pthread_mutex_trylock(&this->access_) == 0) 123 | return true; 124 | else 125 | return false; 126 | } 127 | ; 128 | 129 | /** 130 | * \brief config update 131 | * 132 | * In this function the driver parameters must be updated with the input 133 | * config variable. Then the new configuration state will be stored in the 134 | * Config attribute. 135 | * 136 | * \param new_cfg the new driver configuration state 137 | * 138 | * \param level level in which the update is taken place 139 | */ 140 | void config_update(Config& config, uint32_t level = 0); 141 | 142 | // here define all ackermann_to_odom_alg interface methods to retrieve and set 143 | // the driver parameters 144 | 145 | /** 146 | * \brief Destructor 147 | * 148 | * This destructor is called when the object is about to be destroyed. 149 | * 150 | */ 151 | ~AckermannToOdomAlgorithm(void); 152 | 153 | /** 154 | * \brief Generate new message of odometry 155 | * 156 | * This function gets information of the ackermann state, and the imu, and parse this to new topic 157 | * of odometry type. 158 | * 159 | * @param estimated_ackermann_state is the state of the robot. 160 | * @param covariance is the covariance value of the ackermann state. 161 | * @param virtual_imu_ms is the message of the imu sensor. 162 | * @param odometry is the output of the function. Is odometry message. 163 | * @param odom_trans is the odometry transform in /tf message. 164 | * @param base_trans is the laser transform in /tf message. 165 | */ 166 | void generateNewOdometryMsg2D(ackermann_msgs::AckermannDriveStamped estimated_ackermann_state, 167 | sensor_msgs::Imu virtual_imu_ms, 168 | geometry_msgs::PoseWithCovarianceStamped& odometry_pose, nav_msgs::Odometry& odometry, 169 | geometry_msgs::TransformStamped& odom_trans); 170 | }; 171 | 172 | #endif 173 | -------------------------------------------------------------------------------- /ackermann_to_odom/src/ackermann_to_odom_alg.cpp: -------------------------------------------------------------------------------- 1 | #include "ackermann_to_odom_alg.h" 2 | #include 3 | 4 | AckermannToOdomAlgorithm::AckermannToOdomAlgorithm(void) 5 | { 6 | pthread_mutex_init(&this->access_, NULL); 7 | } 8 | 9 | AckermannToOdomAlgorithm::~AckermannToOdomAlgorithm(void) 10 | { 11 | pthread_mutex_destroy(&this->access_); 12 | } 13 | 14 | void AckermannToOdomAlgorithm::config_update(Config& config, uint32_t level) 15 | { 16 | this->lock(); 17 | 18 | // save the current configuration 19 | this->config_ = config; 20 | 21 | this->unlock(); 22 | } 23 | 24 | // AckermannToOdomAlgorithm Public API 25 | void AckermannToOdomAlgorithm::generateNewOdometryMsg2D(ackermann_msgs::AckermannDriveStamped estimated_ackermann_state, 26 | sensor_msgs::Imu virtual_imu_msg, 27 | geometry_msgs::PoseWithCovarianceStamped& odometry_pose, 28 | nav_msgs::Odometry& odometry, 29 | geometry_msgs::TransformStamped& odom_trans) 30 | { 31 | 32 | int i, j; 33 | float pose_yaw = 0; 34 | static float pose_yaw_prev = 0; 35 | static float pose_x_prev = 0; 36 | static float pose_y_prev = 0; 37 | static double t_1; 38 | static double t_2; 39 | static bool first_exec = true; 40 | float d_vehicle = 1.08; // TODO: get from param and modify git .rm 41 | bool flag_imu = true; // TODO: get from param and modify git .rm 42 | tf::Quaternion quaternion = tf::createQuaternionFromRPY(0, 0, 0);; 43 | 44 | ///////////////////////////////////////////////// 45 | //// POSE AND VELOCITY 46 | //calculate increment of time 47 | if (first_exec) 48 | { 49 | t_2 = (double)ros::Time::now().toSec(); 50 | first_exec = false; 51 | } 52 | t_1 = (double)ros::Time::now().toSec(); 53 | float delta_t = (float)(t_1 - t_2); 54 | t_2 = (double)ros::Time::now().toSec(); 55 | 56 | //read information of low-level sensor 57 | float lineal_speed = estimated_ackermann_state.drive.speed; 58 | float steering_radians = estimated_ackermann_state.drive.steering_angle * M_PI / 180.0; 59 | 60 | //angle 61 | if (flag_imu) 62 | { 63 | tf::Quaternion q(virtual_imu_msg.orientation.x, virtual_imu_msg.orientation.y, virtual_imu_msg.orientation.z, 64 | virtual_imu_msg.orientation.w); 65 | tf::Matrix3x3 m(q); 66 | double roll, pitch, yaw; 67 | m.getRPY(roll, pitch, yaw); 68 | pose_yaw = yaw; 69 | quaternion = tf::createQuaternionFromRPY(0, 0, pose_yaw); 70 | } 71 | else 72 | { 73 | float angular_speed_yaw = (lineal_speed / d_vehicle) * sin(steering_radians); 74 | pose_yaw = pose_yaw_prev + angular_speed_yaw * delta_t; 75 | quaternion = tf::createQuaternionFromRPY(0, 0, pose_yaw); 76 | } 77 | 78 | //pose 79 | float lineal_speed_x = lineal_speed * cos(pose_yaw) * cos(steering_radians); 80 | float lineal_speed_y = lineal_speed * sin(pose_yaw) * cos(steering_radians); 81 | float pose_x = pose_x_prev + lineal_speed_x * delta_t; 82 | float pose_y = pose_y_prev + lineal_speed_y * delta_t; 83 | if (isnan(pose_yaw)) 84 | { 85 | lineal_speed_x = 0.0; 86 | lineal_speed_y = 0.0; 87 | pose_x = 0.0; 88 | pose_y = 0.0; 89 | quaternion = tf::createQuaternionFromRPY(0, 0, 0); 90 | ROS_INFO("isnan(pose_yaw)"); 91 | } 92 | 93 | // For next step 94 | if (abs(pose_x_prev - pose_x) < MAX_DIFF && abs(pose_y_prev - pose_y) < MAX_DIFF) 95 | { 96 | pose_x_prev = pose_x; 97 | pose_y_prev = pose_y; 98 | pose_yaw_prev = pose_yaw; 99 | } 100 | else 101 | { 102 | pose_x = pose_x_prev; 103 | pose_y = pose_y_prev; 104 | pose_yaw = pose_yaw_prev; 105 | quaternion = tf::createQuaternionFromRPY(0, 0, pose_yaw); 106 | } 107 | ///////////////////////////////////////////////// 108 | 109 | ///////////////////////////////////////////////// 110 | //// GENERATE MESSAGE 111 | // Header 112 | odometry.header.stamp = ros::Time::now(); 113 | odometry.header.frame_id = "odom"; 114 | odometry.child_frame_id = "base_link"; 115 | odometry_pose.header.stamp = ros::Time::now(); 116 | odometry_pose.header.frame_id = "odom"; 117 | 118 | // Twist 119 | odometry.twist.twist.linear.x = lineal_speed_x; 120 | odometry.twist.twist.linear.y = lineal_speed_y; 121 | odometry.twist.twist.linear.z = 0; 122 | odometry.twist.twist.angular.x = 0; 123 | odometry.twist.twist.angular.y = 0; 124 | odometry.twist.twist.angular.z = 0; 125 | 126 | // Pose 127 | odometry.pose.pose.position.x = pose_x; 128 | odometry.pose.pose.position.y = pose_y; 129 | odometry.pose.pose.position.z = 0; 130 | odometry.pose.pose.orientation.x = quaternion[0]; 131 | odometry.pose.pose.orientation.y = quaternion[1]; 132 | odometry.pose.pose.orientation.z = quaternion[2]; 133 | odometry.pose.pose.orientation.w = quaternion[3]; 134 | odometry_pose.pose.pose.position.x = pose_x; 135 | odometry_pose.pose.pose.position.y = pose_y; 136 | odometry_pose.pose.pose.position.z = 0; 137 | odometry_pose.pose.pose.orientation.x = quaternion[0]; 138 | odometry_pose.pose.pose.orientation.y = quaternion[1]; 139 | odometry_pose.pose.pose.orientation.z = quaternion[2]; 140 | odometry_pose.pose.pose.orientation.w = quaternion[3]; 141 | odometry_pose.pose.covariance[0] = 0.5; // TODO: calculation of variances !!! 142 | odometry_pose.pose.covariance[7] = 0.5; 143 | odometry_pose.pose.covariance[35] = 0.5; 144 | ///////////////////////////////////////////////// 145 | 146 | //////////////////////////////////////////////////////////////// 147 | //// GENERATE MESSAGES TF 148 | odom_trans.header.frame_id = "odom"; 149 | odom_trans.child_frame_id = "base_link"; 150 | odom_trans.header.stamp = ros::Time::now(); 151 | odom_trans.transform.translation.x = pose_x; 152 | odom_trans.transform.translation.y = pose_y; 153 | odom_trans.transform.translation.z = 0.0; 154 | odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(pose_yaw); 155 | //////////////////////////////////////////////////////////////// 156 | } 157 | -------------------------------------------------------------------------------- /ackermann_to_odom/include/ackermann_to_odom_alg_node.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010-2011 Institut de Robotica i Informatica Industrial, CSIC-UPC. 2 | // Author 3 | // All rights reserved. 4 | // 5 | // This file is part of iri-ros-pkg 6 | // iri-ros-pkg is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU Lesser General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU Lesser General Public License 17 | // along with this program. If not, see . 18 | // 19 | // IMPORTANT NOTE: This code has been generated through a script from the 20 | // iri_ros_scripts. Please do NOT delete any comments to guarantee the correctness 21 | // of the scripts. ROS topics can be easly add by using those scripts. Please 22 | // refer to the IRI wiki page for more information: 23 | // http://wikiri.upc.es/index.php/Robotics_Lab 24 | /** 25 | * \file ackermann_to_odom_alg_node.h 26 | * 27 | * Created on: 04 Sep 2018 28 | * Author: m.a.munoz 29 | */ 30 | 31 | #ifndef _ackermann_to_odom_alg_node_h_ 32 | #define _ackermann_to_odom_alg_node_h_ 33 | 34 | #include 35 | #include "ackermann_to_odom_alg.h" 36 | #include "ackermann_msgs/AckermannDriveStamped.h" 37 | #include "geometry_msgs/PoseWithCovarianceStamped.h" 38 | #include "nav_msgs/Odometry.h" 39 | #include "sensor_msgs/Imu.h" 40 | #include 41 | #include 42 | #include 43 | 44 | // [publisher subscriber headers] 45 | 46 | // [service client headers] 47 | 48 | // [action server client headers] 49 | 50 | /** 51 | * \brief IRI ROS Specific Algorithm Class 52 | * 53 | * Interface with ROS. In this class we specify publishers, subscribers, and callbacks. 54 | */ 55 | class AckermannToOdomAlgNode : public algorithm_base::IriBaseAlgorithm 56 | { 57 | private: 58 | 59 | ackermann_msgs::AckermannDriveStamped estimated_ackermann_state_; 60 | sensor_msgs::Imu virtual_imu_msg_; 61 | geometry_msgs::TransformStamped odom_trans_; 62 | tf::StampedTransform scan_trans_; 63 | tf::TransformBroadcaster broadcaster_; 64 | tf::TransformListener listener_; 65 | nav_msgs::Odometry odometry_; 66 | geometry_msgs::PoseWithCovarianceStamped odometry_pose_; 67 | 68 | // [publisher attributes] 69 | ros::Publisher odometry_publisher_; 70 | ros::Publisher pose_publisher_; 71 | 72 | // [subscriber attributes] 73 | ros::Subscriber estimated_ackermann_subscriber_; 74 | ros::Subscriber covariance_ackermann_subscriber_; 75 | ros::Subscriber virtual_imu_subscriber_; 76 | 77 | /** 78 | * \brief Callback for read imu messages. 79 | */ 80 | void cb_imuData(const sensor_msgs::Imu::ConstPtr& Imu_msg); 81 | 82 | /** 83 | * \brief Callback for read ackermann messages. 84 | */ 85 | void cb_ackermannState(const ackermann_msgs::AckermannDriveStamped::ConstPtr& estimated_ackermann_state_msg); 86 | 87 | // [service attributes] 88 | 89 | // [client attributes] 90 | 91 | // [action server attributes] 92 | 93 | // [action client attributes] 94 | 95 | /** 96 | * \brief config variable 97 | * 98 | * This variable has all the driver parameters defined in the cfg config file. 99 | * Is updated everytime function config_update() is called. 100 | */ 101 | Config config_; 102 | public: 103 | /** 104 | * \brief Constructor 105 | * 106 | * This constructor initializes specific class attributes and all ROS 107 | * communications variables to enable message exchange. 108 | */ 109 | AckermannToOdomAlgNode(void); 110 | 111 | /** 112 | * \brief Destructor 113 | * 114 | * This destructor frees all necessary dynamic memory allocated within this 115 | * this class. 116 | */ 117 | ~AckermannToOdomAlgNode(void); 118 | 119 | protected: 120 | /** 121 | * \brief main node thread 122 | * 123 | * This is the main thread node function. Code written here will be executed 124 | * in every node loop while the algorithm is on running state. Loop frequency 125 | * can be tuned by modifying loop_rate attribute. 126 | * 127 | * Here data related to the process loop or to ROS topics (mainly data structs 128 | * related to the MSG and SRV files) must be updated. ROS publisher objects 129 | * must publish their data in this process. ROS client servers may also 130 | * request data to the corresponding server topics. 131 | * 132 | * In this point we need to read some parameters from rosparam: 133 | * 134 | * @param odom_in_tf (bool) if this parameter is true, the odometry will publish in the /tf messages 135 | * @param x_tf (float) is the transform of the laser in x axis. 136 | * @param yaw_tf (float) is the transform of the laser in yaw angle. 137 | * @param frame_id (string) is the name of origin frame. 138 | * @param child_id (string) is the name of laser frame. 139 | * 140 | */ 141 | void mainNodeThread(void); 142 | 143 | /** 144 | * \brief dynamic reconfigure server callback 145 | * 146 | * This method is called whenever a new configuration is received through 147 | * the dynamic reconfigure. The derivated generic algorithm class must 148 | * implement it. 149 | * 150 | * \param config an object with new configuration from all algorithm 151 | * parameters defined in the config file. 152 | * \param level integer referring the level in which the configuration 153 | * has been changed. 154 | */ 155 | void node_config_update(Config &config, uint32_t level); 156 | 157 | /** 158 | * \brief node add diagnostics 159 | * 160 | * In this abstract function additional ROS diagnostics applied to the 161 | * specific algorithms may be added. 162 | */ 163 | void addNodeDiagnostics(void); 164 | 165 | // [diagnostic functions] 166 | 167 | // [test functions] 168 | }; 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /gps_to_odom/include/gps_to_odom_alg_node.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010-2011 Institut de Robotica i Informatica Industrial, CSIC-UPC. 2 | // Author 3 | // All rights reserved. 4 | // 5 | // This file is part of iri-ros-pkg 6 | // iri-ros-pkg is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU Lesser General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU Lesser General Public License 17 | // along with this program. If not, see . 18 | // 19 | // IMPORTANT NOTE: This code has been generated through a script from the 20 | // iri_ros_scripts. Please do NOT delete any comments to guarantee the correctness 21 | // of the scripts. ROS topics can be easly add by using those scripts. Please 22 | // refer to the IRI wiki page for more information: 23 | // http://wikiri.upc.es/index.php/Robotics_Lab 24 | /** 25 | * \file gps_to_odom_alg_node.h 26 | * 27 | * Created on: 04 Dec 2018 28 | * Author: m.a.munoz 29 | */ 30 | 31 | #ifndef _gps_to_odom_alg_node_h_ 32 | #define _gps_to_odom_alg_node_h_ 33 | 34 | #include 35 | #include "gps_to_odom_alg.h" 36 | #include "tf_conversions/tf_eigen.h" 37 | #include 38 | #include 39 | 40 | // [publisher subscriber headers] 41 | 42 | // [service client headers] 43 | 44 | // [action server client headers] 45 | 46 | /** 47 | * \brief IRI ROS Specific Algorithm Class 48 | * 49 | */ 50 | class GpsToOdomAlgNode : public algorithm_base::IriBaseAlgorithm 51 | { 52 | private: 53 | 54 | bool flag_publish_odom_; 55 | bool flag_gnss_position_received_; 56 | bool flag_gnss_velocity_received_; 57 | float max_speed_; 58 | float min_speed_; 59 | std::string frame_id_; 60 | nav_msgs::Odometry odom_gps_; 61 | tf::StampedTransform utm_trans_; 62 | tf::TransformListener listener_; 63 | 64 | // [publisher attributes] 65 | ros::Publisher odom_gps_pub_; 66 | 67 | // [subscriber attributes] 68 | ros::Subscriber sim_fix_sub_; 69 | ros::Subscriber sim_vel_sub_; 70 | ros::Subscriber bot_fix_sub_; 71 | ros::Subscriber bot_vel_sub_; 72 | ros::Subscriber nco_vel_sub_; // nco = no covariance 73 | 74 | 75 | /** 76 | * \brief callback for read gps fix messages (from gazebo) 77 | * This message can be read from different localization sources by remapping in the 78 | * execution of the node. 79 | */ 80 | void cb_getSimGpsFixMsg(const sensor_msgs::NavSatFix::ConstPtr& fix_msg); 81 | 82 | /** 83 | * \brief callback for read fix velocity messages (from gazebo) 84 | * This message can be read from different localization sources by remapping in the 85 | * execution of the node. 86 | */ 87 | void cb_getSimGpsVelMsg(const geometry_msgs::Vector3Stamped::ConstPtr& vel_msg); 88 | 89 | /** 90 | * \brief callback for read gps fix messages (from sensor) 91 | * This message can be read from different localization sources by remapping in the 92 | * execution of the node. 93 | */ 94 | void cb_getBotGpsFixMsg(const nav_msgs::Odometry::ConstPtr& fix_msg); 95 | 96 | /** 97 | * \brief callback for read fix velocity messages (from sensor) 98 | * This message can be read from different localization sources by remapping in the 99 | * execution of the node. 100 | */ 101 | void cb_getBotGpsVelMsg(const geometry_msgs::TwistWithCovarianceStamped::ConstPtr& vel_msg); 102 | 103 | /** 104 | * \brief callback for read fix velocity messages (from sensor) 105 | * This message can be read from different localization sources by remapping in the 106 | * execution of the node. 107 | */ 108 | void cb_getNcoGpsVelMsg(const geometry_msgs::TwistStamped::ConstPtr& vel_msg); 109 | 110 | // [service attributes] 111 | 112 | // [client attributes] 113 | 114 | // [action server attributes] 115 | 116 | // [action client attributes] 117 | 118 | /** 119 | * \brief config variable 120 | * 121 | * This variable has all the driver parameters defined in the cfg config file. 122 | * Is updated everytime function config_update() is called. 123 | */ 124 | Config config_; 125 | public: 126 | /** 127 | * \brief Constructor 128 | * 129 | * This constructor initializes specific class attributes and all ROS 130 | * communications variables to enable message exchange. 131 | */ 132 | GpsToOdomAlgNode(void); 133 | 134 | /** 135 | * \brief Destructor 136 | * 137 | * This destructor frees all necessary dynamic memory allocated within this 138 | * this class. 139 | */ 140 | ~GpsToOdomAlgNode(void); 141 | 142 | protected: 143 | /** 144 | * \brief main node thread 145 | * 146 | * This is the main thread node function. Code written here will be executed 147 | * in every node loop while the algorithm is on running state. Loop frequency 148 | * can be tuned by modifying loop_rate attribute. 149 | * 150 | * Here data related to the process loop or to ROS topics (mainly data structs 151 | * related to the MSG and SRV files) must be updated. ROS publisher objects 152 | * must publish their data in this process. ROS client servers may also 153 | * request data to the corresponding server topics. 154 | */ 155 | void mainNodeThread(void); 156 | 157 | /** 158 | * \brief dynamic reconfigure server callback 159 | * 160 | * This method is called whenever a new configuration is received through 161 | * the dynamic reconfigure. The derivated generic algorithm class must 162 | * implement it. 163 | * 164 | * \param config an object with new configuration from all algorithm 165 | * parameters defined in the config file. 166 | * \param level integer referring the level in which the configuration 167 | * has been changed. 168 | */ 169 | void node_config_update(Config &config, uint32_t level); 170 | 171 | /** 172 | * \brief node add diagnostics 173 | * 174 | * In this abstract function additional ROS diagnostics applied to the 175 | * specific algorithms may be added. 176 | */ 177 | void addNodeDiagnostics(void); 178 | 179 | // [diagnostic functions] 180 | 181 | // [test functions] 182 | }; 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /dualquat_LOAM/rviz/kitti_fov.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 0 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: ~ 7 | Splitter Ratio: 0.6264705657958984 8 | Tree Height: 892 9 | - Class: rviz/Selection 10 | Name: Selection 11 | - Class: rviz/Tool Properties 12 | Expanded: 13 | - /2D Pose Estimate1 14 | - /2D Nav Goal1 15 | - /Publish Point1 16 | Name: Tool Properties 17 | Splitter Ratio: 0.5886790156364441 18 | - Class: rviz/Views 19 | Expanded: 20 | - /Current View1 21 | Name: Views 22 | Splitter Ratio: 0.5 23 | - Class: rviz/Time 24 | Name: Time 25 | SyncMode: 0 26 | SyncSource: fullmap 27 | Preferences: 28 | PromptSaveOnExit: true 29 | Toolbars: 30 | toolButtonStyle: 2 31 | Visualization Manager: 32 | Class: "" 33 | Displays: 34 | - Alpha: 0.5 35 | Cell Size: 1 36 | Class: rviz/Grid 37 | Color: 160; 160; 164 38 | Enabled: false 39 | Line Style: 40 | Line Width: 0.029999999329447746 41 | Value: Lines 42 | Name: Grid 43 | Normal Cell Count: 0 44 | Offset: 45 | X: 0 46 | Y: 0 47 | Z: 0 48 | Plane: XY 49 | Plane Cell Count: 200 50 | Reference Frame: 51 | Value: false 52 | - Alpha: 1 53 | Class: rviz/Axes 54 | Enabled: true 55 | Length: 2 56 | Name: Axes 57 | Radius: 0.5 58 | Reference Frame: 59 | Show Trail: true 60 | Value: true 61 | - Alpha: 1 62 | Class: rviz/Axes 63 | Enabled: true 64 | Length: 2 65 | Name: Velodyne 66 | Radius: 0.5 67 | Reference Frame: velodyne 68 | Show Trail: false 69 | Value: true 70 | - Alpha: 0.5 71 | Autocompute Intensity Bounds: true 72 | Autocompute Value Bounds: 73 | Max Value: -33.894691467285156 74 | Min Value: -121.7796630859375 75 | Value: true 76 | Axis: Y 77 | Channel Name: intensity 78 | Class: rviz/PointCloud2 79 | Color: 255; 255; 255 80 | Color Transformer: Intensity 81 | Decay Time: 1000 82 | Enabled: true 83 | Invert Rainbow: true 84 | Max Color: 255; 255; 255 85 | Min Color: 0; 0; 0 86 | Name: fullmap 87 | Position Transformer: XYZ 88 | Queue Size: 10 89 | Selectable: true 90 | Size (Pixels): 1 91 | Size (m): 0.05000000074505806 92 | Style: Flat Squares 93 | Topic: /output_cloud 94 | Unreliable: false 95 | Use Fixed Frame: true 96 | Use rainbow: true 97 | Value: true 98 | - Alpha: 1 99 | Buffer Length: 1 100 | Class: rviz/Path 101 | Color: 25; 255; 0 102 | Enabled: true 103 | Head Diameter: 0.30000001192092896 104 | Head Length: 0.5 105 | Length: 0.5 106 | Line Style: Lines 107 | Line Width: 5 108 | Name: Path 109 | Offset: 110 | X: 0 111 | Y: 0 112 | Z: 0 113 | Pose Color: 25; 255; 255 114 | Pose Style: Axes 115 | Queue Size: 10 116 | Radius: 0.20000000298023224 117 | Shaft Diameter: 0.25 118 | Shaft Length: 0.5 119 | Topic: /dualquat_odom/trajectory 120 | Unreliable: false 121 | Value: true 122 | Enabled: true 123 | Global Options: 124 | Background Color: 255; 255; 255 125 | Default Light: true 126 | Fixed Frame: map 127 | Frame Rate: 10 128 | Name: root 129 | Tools: 130 | - Class: rviz/Interact 131 | Hide Inactive Objects: true 132 | - Class: rviz/MoveCamera 133 | - Class: rviz/Select 134 | - Class: rviz/FocusCamera 135 | - Class: rviz/Measure 136 | - Class: rviz/SetInitialPose 137 | Theta std deviation: 0.2617993950843811 138 | Topic: /initialpose 139 | X std deviation: 0.5 140 | Y std deviation: 0.5 141 | - Class: rviz/SetGoal 142 | Topic: /move_base_simple/goal 143 | - Class: rviz/PublishPoint 144 | Single click: true 145 | Topic: /clicked_point 146 | Value: true 147 | Views: 148 | Current: 149 | Class: rviz/ThirdPersonFollower 150 | Distance: 48.187400817871094 151 | Enable Stereo Rendering: 152 | Stereo Eye Separation: 0.05999999865889549 153 | Stereo Focal Distance: 1 154 | Swap Stereo Eyes: false 155 | Value: false 156 | Field of View: 0.7853981852531433 157 | Focal Point: 158 | X: -2.4139204025268555 159 | Y: -12.639135360717773 160 | Z: 0 161 | Focal Shape Fixed Size: true 162 | Focal Shape Size: 0.05000000074505806 163 | Invert Z Axis: false 164 | Name: Current View 165 | Near Clip Distance: 0.009999999776482582 166 | Pitch: 1.5697963237762451 167 | Target Frame: velodyne 168 | Yaw: -1.5700000524520874 169 | Saved: ~ 170 | Window Geometry: 171 | Displays: 172 | collapsed: true 173 | Height: 1043 174 | Hide Left Dock: true 175 | Hide Right Dock: true 176 | QMainWindow State: 000000ff00000000fd000000040000000000000186000003b9fc020000000efb000000100044006900730070006c006100790073000000003d000003b9000000c900fffffffb0000000a0049006d00610067006500000002a7000001330000000000000000fb0000001200530065006c0065006300740069006f006e000000003b000000f30000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000abfb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d006100670065000000033e0000020c0000000000000000fb0000000a0049006d00610067006500000002ec000000ec0000000000000000fb0000000a0049006d006100670065000000003d000002010000000000000000fb0000000a0049006d0061006700650000000212000001c80000000000000000fb0000000a0049006d00610067006500000003d50000002100000000000000000000000100000152000003b9fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d000003b9000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000738000000a9fc0100000005fb0000000a0049006d0061006700650000000000000007380000000000000000fb0000000c00430061006d0065007200610000000000000007380000000000000000fb0000000c00430061006d0065007200610000000000000007380000000000000000fc000000000000041a0000000000fffffffa000000000200000002fb0000000a0049006d0061006700650000000000ffffffff0000000000000000fb0000000a0049006d006100670065000000003d000000a90000000000000000fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073d00000039fc0100000002fb0000000800540069006d006500000000000000073d000003bc00fffffffb0000000800540069006d0065010000000000000450000000000000000000000738000003b900000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 177 | Selection: 178 | collapsed: false 179 | Time: 180 | collapsed: false 181 | Tool Properties: 182 | collapsed: false 183 | Views: 184 | collapsed: true 185 | Width: 1848 186 | X: 1992 187 | Y: 0 188 | -------------------------------------------------------------------------------- /dualquat_LOAM/src/laserMappingClass.cpp: -------------------------------------------------------------------------------- 1 | // The mapping process is based on the FLOAM code. 2 | // Author of FLOAM: Wang Han 3 | // Email wh200720041@gmail.com 4 | // Author of LiDAR-Odometry_DQ: Edison Velasco 5 | // Email edison.velasco@ua.es 6 | 7 | #include "laserMappingClass.h" 8 | 9 | void LaserMappingClass::init(double map_resolution){ 10 | //init map 11 | //init can have real object, but future added block does not need 12 | for(int i=0;i::Ptr>> map_height_temp; 14 | for(int j=0;j::Ptr> map_depth_temp; 16 | for(int k=0;k::Ptr point_cloud_temp(new pcl::PointCloud); 18 | map_depth_temp.push_back(point_cloud_temp); 19 | } 20 | map_height_temp.push_back(map_depth_temp); 21 | } 22 | map.push_back(map_height_temp); 23 | } 24 | 25 | origin_in_map_x = LASER_CELL_RANGE_HORIZONTAL; 26 | origin_in_map_y = LASER_CELL_RANGE_HORIZONTAL; 27 | origin_in_map_z = LASER_CELL_RANGE_VERTICAL; 28 | map_width = LASER_CELL_RANGE_HORIZONTAL*2+1; 29 | map_height = LASER_CELL_RANGE_HORIZONTAL*2+1; 30 | map_depth = LASER_CELL_RANGE_HORIZONTAL*2+1; 31 | 32 | //downsampling size 33 | downSizeFilter.setLeafSize(map_resolution, map_resolution, map_resolution); 34 | } 35 | 36 | void LaserMappingClass::addWidthCellNegative(void){ 37 | std::vector::Ptr>> map_height_temp; 38 | for(int j=0; j < map_height;j++){ 39 | std::vector::Ptr> map_depth_temp; 40 | for(int k=0;k< map_depth;k++){ 41 | pcl::PointCloud::Ptr point_cloud_temp; 42 | map_depth_temp.push_back(point_cloud_temp); 43 | } 44 | map_height_temp.push_back(map_depth_temp); 45 | } 46 | map.insert(map.begin(), map_height_temp); 47 | 48 | origin_in_map_x++; 49 | map_width++; 50 | } 51 | void LaserMappingClass::addWidthCellPositive(void){ 52 | std::vector::Ptr>> map_height_temp; 53 | for(int j=0; j < map_height;j++){ 54 | std::vector::Ptr> map_depth_temp; 55 | for(int k=0;k< map_depth;k++){ 56 | pcl::PointCloud::Ptr point_cloud_temp; 57 | map_depth_temp.push_back(point_cloud_temp); 58 | } 59 | map_height_temp.push_back(map_depth_temp); 60 | } 61 | map.push_back(map_height_temp); 62 | map_width++; 63 | } 64 | void LaserMappingClass::addHeightCellNegative(void){ 65 | for(int i=0; i < map_width;i++){ 66 | std::vector::Ptr> map_depth_temp; 67 | for(int k=0;k::Ptr point_cloud_temp; 69 | map_depth_temp.push_back(point_cloud_temp); 70 | } 71 | map[i].insert(map[i].begin(), map_depth_temp); 72 | } 73 | origin_in_map_y++; 74 | map_height++; 75 | } 76 | void LaserMappingClass::addHeightCellPositive(void){ 77 | for(int i=0; i < map_width;i++){ 78 | std::vector::Ptr> map_depth_temp; 79 | for(int k=0;k::Ptr point_cloud_temp; 81 | map_depth_temp.push_back(point_cloud_temp); 82 | } 83 | map[i].push_back(map_depth_temp); 84 | } 85 | map_height++; 86 | } 87 | void LaserMappingClass::addDepthCellNegative(void){ 88 | for(int i=0; i < map_width;i++){ 89 | for(int j=0;j< map_height;j++){ 90 | pcl::PointCloud::Ptr point_cloud_temp; 91 | map[i][j].insert(map[i][j].begin(), point_cloud_temp); 92 | } 93 | } 94 | origin_in_map_z++; 95 | map_depth++; 96 | } 97 | void LaserMappingClass::addDepthCellPositive(void){ 98 | for(int i=0; i < map_width;i++){ 99 | for(int j=0;j< map_height;j++){ 100 | pcl::PointCloud::Ptr point_cloud_temp; 101 | map[i][j].push_back(point_cloud_temp); 102 | } 103 | } 104 | map_depth++; 105 | } 106 | 107 | //extend map is points exceed size 108 | void LaserMappingClass::checkPoints(int& x, int& y, int& z){ 109 | 110 | while(x + LASER_CELL_RANGE_HORIZONTAL> map_width-1){ 111 | addWidthCellPositive(); 112 | } 113 | while(x-LASER_CELL_RANGE_HORIZONTAL<0){ 114 | addWidthCellNegative(); 115 | x++; 116 | } 117 | while(y + LASER_CELL_RANGE_HORIZONTAL> map_height-1){ 118 | addHeightCellPositive(); 119 | } 120 | while(y-LASER_CELL_RANGE_HORIZONTAL<0){ 121 | addHeightCellNegative(); 122 | y++; 123 | } 124 | while(z + LASER_CELL_RANGE_VERTICAL> map_depth-1){ 125 | addDepthCellPositive(); 126 | } 127 | while(z-LASER_CELL_RANGE_VERTICAL<0){ 128 | addDepthCellNegative(); 129 | z++; 130 | } 131 | 132 | //initialize 133 | //create object if area is null 134 | for(int i=x-LASER_CELL_RANGE_HORIZONTAL;i::Ptr point_cloud_temp(new pcl::PointCloud()); 139 | map[i][j][k] = point_cloud_temp; 140 | } 141 | 142 | } 143 | 144 | } 145 | 146 | } 147 | } 148 | 149 | //update points to map 150 | void LaserMappingClass::updateCurrentPointsToMap(const pcl::PointCloud::Ptr& pc_in, const Eigen::Isometry3d& pose_current){ 151 | 152 | int currentPosIdX = int(std::floor(pose_current.translation().x() / LASER_CELL_WIDTH + 0.5)) + origin_in_map_x; 153 | int currentPosIdY = int(std::floor(pose_current.translation().y() / LASER_CELL_HEIGHT + 0.5)) + origin_in_map_y; 154 | int currentPosIdZ = int(std::floor(pose_current.translation().z() / LASER_CELL_DEPTH + 0.5)) + origin_in_map_z; 155 | 156 | //check is submap is null 157 | checkPoints(currentPosIdX,currentPosIdY,currentPosIdZ); 158 | 159 | pcl::PointCloud::Ptr transformed_pc(new pcl::PointCloud()); 160 | pcl::transformPointCloud(*pc_in, *transformed_pc, pose_current.cast()); 161 | 162 | //save points 163 | for (int i = 0; i < (int)transformed_pc->points.size(); i++) 164 | { 165 | pcl::PointXYZI point_temp = transformed_pc->points[i]; 166 | //for visualization only 167 | try 168 | { 169 | point_temp.intensity = std::min(1.0 , std::max(pc_in->points[i].z+2.0, 0.0) / 5); 170 | } 171 | catch(const std::exception& e) 172 | { 173 | //std::cerr << e.what() << '\n'; 174 | } 175 | 176 | 177 | int currentPointIdX = int(std::floor(point_temp.x / LASER_CELL_WIDTH + 0.5)) + origin_in_map_x; 178 | int currentPointIdY = int(std::floor(point_temp.y / LASER_CELL_HEIGHT + 0.5)) + origin_in_map_y; 179 | int currentPointIdZ = int(std::floor(point_temp.z / LASER_CELL_DEPTH + 0.5)) + origin_in_map_z; 180 | 181 | map[currentPointIdX][currentPointIdY][currentPointIdZ]->push_back(point_temp); 182 | 183 | } 184 | 185 | //filtering points 186 | for(int i=currentPosIdX-LASER_CELL_RANGE_HORIZONTAL;i::Ptr LaserMappingClass::getMap(void){ 200 | pcl::PointCloud::Ptr laserCloudMap = pcl::PointCloud::Ptr(new pcl::PointCloud()); 201 | for (int i = 0; i < map_width; i++){ 202 | for (int j = 0; j < map_height; j++){ 203 | for (int k = 0; k < map_depth; k++){ 204 | if(map[i][j][k]!=NULL){ 205 | *laserCloudMap += *(map[i][j][k]); 206 | } 207 | } 208 | } 209 | } 210 | return laserCloudMap; 211 | } 212 | 213 | LaserMappingClass::LaserMappingClass(){ 214 | 215 | } 216 | 217 | -------------------------------------------------------------------------------- /odom_estimation_pc/rviz/odomEstimation.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | - /TF1 10 | - /TF1/Frames1 11 | - /TF1/Tree1 12 | - /PointCloud22 13 | Splitter Ratio: 0.5 14 | Tree Height: 580 15 | - Class: rviz/Selection 16 | Name: Selection 17 | - Class: rviz/Tool Properties 18 | Expanded: 19 | - /2D Pose Estimate1 20 | - /2D Nav Goal1 21 | - /Publish Point1 22 | Name: Tool Properties 23 | Splitter Ratio: 0.5886790156364441 24 | - Class: rviz/Views 25 | Expanded: 26 | - /Current View1 27 | Name: Views 28 | Splitter Ratio: 0.5 29 | - Class: rviz/Time 30 | Experimental: false 31 | Name: Time 32 | SyncMode: 0 33 | SyncSource: Image 34 | Preferences: 35 | PromptSaveOnExit: true 36 | Toolbars: 37 | toolButtonStyle: 2 38 | Visualization Manager: 39 | Class: "" 40 | Displays: 41 | - Alpha: 0.5 42 | Cell Size: 1 43 | Class: rviz/Grid 44 | Color: 160; 160; 164 45 | Enabled: true 46 | Line Style: 47 | Line Width: 0.029999999329447746 48 | Value: Lines 49 | Name: Grid 50 | Normal Cell Count: 0 51 | Offset: 52 | X: 0 53 | Y: 0 54 | Z: 0 55 | Plane: XY 56 | Plane Cell Count: 10 57 | Reference Frame: 58 | Value: true 59 | - Alpha: 1 60 | Buffer Length: 1 61 | Class: rviz/Path 62 | Color: 25; 255; 0 63 | Enabled: true 64 | Head Diameter: 0.30000001192092896 65 | Head Length: 0.20000000298023224 66 | Length: 0.30000001192092896 67 | Line Style: Lines 68 | Line Width: 0.029999999329447746 69 | Name: Path 70 | Offset: 71 | X: 0 72 | Y: 0 73 | Z: 0 74 | Pose Color: 255; 85; 255 75 | Pose Style: None 76 | Radius: 0.029999999329447746 77 | Shaft Diameter: 0.10000000149011612 78 | Shaft Length: 0.10000000149011612 79 | Topic: /base_link/trajectory 80 | Unreliable: false 81 | Value: true 82 | - Class: rviz/TF 83 | Enabled: true 84 | Frame Timeout: 15 85 | Frames: 86 | All Enabled: true 87 | base_link: 88 | Value: true 89 | odom: 90 | Value: true 91 | Marker Scale: 3 92 | Name: TF 93 | Show Arrows: true 94 | Show Axes: true 95 | Show Names: true 96 | Tree: 97 | odom: 98 | base_link: 99 | {} 100 | Update Interval: 0 101 | Value: true 102 | - Alpha: 1 103 | Autocompute Intensity Bounds: true 104 | Autocompute Value Bounds: 105 | Max Value: 12.31192398071289 106 | Min Value: -2.22633695602417 107 | Value: true 108 | Axis: Z 109 | Channel Name: intensity 110 | Class: rviz/PointCloud2 111 | Color: 255; 255; 255 112 | Color Transformer: FlatColor 113 | Decay Time: 0 114 | Enabled: true 115 | Invert Rainbow: false 116 | Max Color: 255; 255; 255 117 | Min Color: 0; 0; 0 118 | Name: PointCloud2 119 | Position Transformer: XYZ 120 | Queue Size: 10 121 | Selectable: true 122 | Size (Pixels): 1 123 | Size (m): 0.10000000149011612 124 | Style: Points 125 | Topic: /pc_surf 126 | Unreliable: false 127 | Use Fixed Frame: true 128 | Use rainbow: true 129 | Value: true 130 | - Alpha: 1 131 | Autocompute Intensity Bounds: true 132 | Autocompute Value Bounds: 133 | Max Value: 11.299528121948242 134 | Min Value: -1.4916749000549316 135 | Value: true 136 | Axis: Z 137 | Channel Name: intensity 138 | Class: rviz/PointCloud2 139 | Color: 239; 41; 41 140 | Color Transformer: FlatColor 141 | Decay Time: 0 142 | Enabled: true 143 | Invert Rainbow: false 144 | Max Color: 255; 255; 255 145 | Min Color: 0; 0; 0 146 | Name: PointCloud2 147 | Position Transformer: XYZ 148 | Queue Size: 10 149 | Selectable: true 150 | Size (Pixels): 3 151 | Size (m): 0.10000000149011612 152 | Style: Points 153 | Topic: /pc_edge 154 | Unreliable: false 155 | Use Fixed Frame: true 156 | Use rainbow: true 157 | Value: true 158 | - Class: rviz/Image 159 | Enabled: true 160 | Image Topic: /eq_image 161 | Max Value: 1 162 | Median window: 5 163 | Min Value: 0 164 | Name: Image 165 | Normalize Range: true 166 | Queue Size: 2 167 | Transport Hint: raw 168 | Unreliable: false 169 | Value: true 170 | - Class: rviz/Image 171 | Enabled: false 172 | Image Topic: /depth_image 173 | Max Value: 1 174 | Median window: 5 175 | Min Value: 0 176 | Name: Image 177 | Normalize Range: true 178 | Queue Size: 2 179 | Transport Hint: raw 180 | Unreliable: false 181 | Value: false 182 | - Class: rviz/Image 183 | Enabled: false 184 | Image Topic: /edge_image 185 | Max Value: 1 186 | Median window: 5 187 | Min Value: 0 188 | Name: Image 189 | Normalize Range: true 190 | Queue Size: 2 191 | Transport Hint: raw 192 | Unreliable: false 193 | Value: false 194 | - Class: rviz/Image 195 | Enabled: false 196 | Image Topic: /surf_image 197 | Max Value: 1 198 | Median window: 5 199 | Min Value: 0 200 | Name: Image 201 | Normalize Range: true 202 | Queue Size: 2 203 | Transport Hint: raw 204 | Unreliable: false 205 | Value: false 206 | Enabled: true 207 | Global Options: 208 | Background Color: 48; 48; 48 209 | Default Light: true 210 | Fixed Frame: odom 211 | Frame Rate: 30 212 | Name: root 213 | Tools: 214 | - Class: rviz/Interact 215 | Hide Inactive Objects: true 216 | - Class: rviz/MoveCamera 217 | - Class: rviz/Select 218 | - Class: rviz/FocusCamera 219 | - Class: rviz/Measure 220 | - Class: rviz/SetInitialPose 221 | Theta std deviation: 0.2617993950843811 222 | Topic: /initialpose 223 | X std deviation: 0.5 224 | Y std deviation: 0.5 225 | - Class: rviz/SetGoal 226 | Topic: /move_base_simple/goal 227 | - Class: rviz/PublishPoint 228 | Single click: true 229 | Topic: /clicked_point 230 | Value: true 231 | Views: 232 | Current: 233 | Class: rviz/Orbit 234 | Distance: 166.67564392089844 235 | Enable Stereo Rendering: 236 | Stereo Eye Separation: 0.05999999865889549 237 | Stereo Focal Distance: 1 238 | Swap Stereo Eyes: false 239 | Value: false 240 | Focal Point: 241 | X: -0.09540155529975891 242 | Y: 1.8425703048706055 243 | Z: -7.686331748962402 244 | Focal Shape Fixed Size: true 245 | Focal Shape Size: 0.05000000074505806 246 | Invert Z Axis: false 247 | Name: Current View 248 | Near Clip Distance: 0.009999999776482582 249 | Pitch: 1.5697963237762451 250 | Target Frame: 251 | Value: Orbit (rviz) 252 | Yaw: 3.115448474884033 253 | Saved: ~ 254 | Window Geometry: 255 | Displays: 256 | collapsed: false 257 | Height: 1052 258 | Hide Left Dock: false 259 | Hide Right Dock: true 260 | Image: 261 | collapsed: false 262 | QMainWindow State: 000000ff00000000fd00000004000000000000016a000002cffc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c00610079007301000000ec000002cf000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000351fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d00000351000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000780000000a9fc0100000002fc00000000000007800000007b00fffffffa000000030200000004fb0000000a0049006d0061006700650100000000ffffffff0000001600fffffffb0000000a0049006d0061006700650100000000ffffffff0000001600fffffffb0000000a0049006d0061006700650100000000ffffffff0000001600fffffffb0000000a0049006d006100670065010000003d000000a90000001600fffffffb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007800000003efc0100000002fb0000000800540069006d0065010000000000000780000002eb00fffffffb0000000800540069006d0065010000000000000450000000000000000000000610000002cf00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 263 | Selection: 264 | collapsed: false 265 | Time: 266 | collapsed: false 267 | Tool Properties: 268 | collapsed: false 269 | Views: 270 | collapsed: true 271 | Width: 1920 272 | X: 1920 273 | Y: 0 274 | -------------------------------------------------------------------------------- /odom_estimation_pc/src/odomEstimationNode.cpp: -------------------------------------------------------------------------------- 1 | // Author of FLOAM: Wang Han 2 | // Email wh200720041@gmail.com 3 | // Homepage https://wanghan.pro 4 | 5 | // Author of Lilo: Edison Velasco 6 | // Email evs25@alu.ua.es 7 | 8 | //c++ lib 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //ros lib 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | //pcl lib 25 | #include 26 | #include 27 | #include 28 | 29 | //local lib 30 | #include "lidar.h" 31 | #include "odomEstimationClass.h" 32 | 33 | OdomEstimationClass odomEstimation; 34 | std::mutex mutex_lock; 35 | std::queue pointCloudEdgeBuf; 36 | std::queue pointCloudSurfBuf; 37 | 38 | std::string childframeID = "os_sesnor"; 39 | std::string edge_pcl = "/pcl_edge"; 40 | std::string surf_pcl = "/pcl_surf"; 41 | 42 | lidar::Lidar lidar_param; 43 | 44 | ros::Publisher pubLaserOdometry; 45 | ros::Publisher pubOdometryDiff; 46 | 47 | ros::Publisher time_average; 48 | 49 | 50 | void velodyneSurfHandler(const sensor_msgs::PointCloud2ConstPtr &laserCloudMsg) 51 | { 52 | mutex_lock.lock(); 53 | pointCloudSurfBuf.push(laserCloudMsg); 54 | mutex_lock.unlock(); 55 | } 56 | void velodyneEdgeHandler(const sensor_msgs::PointCloud2ConstPtr &laserCloudMsg) 57 | { 58 | 59 | mutex_lock.lock(); 60 | pointCloudEdgeBuf.push(laserCloudMsg); 61 | mutex_lock.unlock(); 62 | } 63 | 64 | bool is_odom_inited = false; 65 | double total_time =0, cropBox_len, surf_limit; 66 | int total_frame=0; 67 | bool clear_map; 68 | void odom_estimation(){ 69 | 70 | float time_delay = 0; 71 | 72 | Eigen::Quaterniond q_diff; 73 | Eigen::Vector3d t_diff; 74 | Eigen::Isometry3d odom_prev = Eigen::Isometry3d::Identity();; 75 | 76 | 77 | while(1){ 78 | if(!pointCloudEdgeBuf.empty() && !pointCloudSurfBuf.empty()){ 79 | 80 | mutex_lock.lock(); 81 | 82 | pcl::PointCloud::Ptr pointcloud_surf_in(new pcl::PointCloud()); 83 | pcl::PointCloud::Ptr pointcloud_edge_in(new pcl::PointCloud()); 84 | pcl::fromROSMsg(*pointCloudEdgeBuf.front(), *pointcloud_edge_in); 85 | pcl::fromROSMsg(*pointCloudSurfBuf.front(), *pointcloud_surf_in); 86 | ros::Time pointcloud_time = (pointCloudSurfBuf.front())->header.stamp; 87 | pointCloudEdgeBuf.pop(); 88 | pointCloudSurfBuf.pop(); 89 | mutex_lock.unlock(); 90 | 91 | if(is_odom_inited == false){ 92 | odomEstimation.initMapWithPoints(pointcloud_edge_in, pointcloud_surf_in); 93 | is_odom_inited = true; 94 | ROS_INFO("odom inited"); 95 | }else{ 96 | std::chrono::time_point start, end; 97 | start = std::chrono::system_clock::now(); 98 | odomEstimation.updatePointsToMap(pointcloud_edge_in, pointcloud_surf_in, clear_map, cropBox_len); 99 | end = std::chrono::system_clock::now(); 100 | std::chrono::duration elapsed_seconds = end - start; 101 | total_frame++; 102 | float time_temp = elapsed_seconds.count() * 1000.0; 103 | total_time+=time_temp; 104 | time_delay = total_time/total_frame; 105 | ROS_INFO("average odom estimation time %f mS", time_delay); 106 | time_delay = time_delay/1000.0; 107 | } 108 | 109 | 110 | Eigen::Quaterniond q_current(odomEstimation.odom.rotation()); 111 | Eigen::Vector3d t_current = odomEstimation.odom.translation(); 112 | 113 | /////////////////////////////////////////////////////// 114 | // Project to 2D!!! 115 | t_current.z() = 0.0; 116 | double siny_cosp = 2 * (q_current.w() * q_current.z() + q_current.x() * q_current.y()); 117 | double cosy_cosp = 1 - 2 * (q_current.y() * q_current.y() + q_current.z() * q_current.z()); 118 | double yaw = std::atan2(siny_cosp, cosy_cosp); 119 | Eigen::AngleAxisd yaw_angle(yaw, Eigen::Vector3d::UnitZ()); 120 | q_current = yaw_angle; 121 | /////////////////////////////////////////////////////// 122 | /////////////////////////////////////////////////////// 123 | 124 | static tf::TransformBroadcaster br; 125 | tf::Transform transform; 126 | transform.setOrigin( tf::Vector3(t_current.x(), t_current.y(), t_current.z()) ); 127 | tf::Quaternion q(q_current.x(),q_current.y(),q_current.z(),q_current.w()); 128 | transform.setRotation(q); 129 | br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "odom", "os_sensor")); 130 | 131 | //// TODO: FROM URDF!!!!!!!! 132 | transform.setOrigin( tf::Vector3(-0.55, 0.0, -0.645) ); 133 | tf::Quaternion q2(0.0, 0.0, 0.0, 1.0); 134 | transform.setRotation(q2); 135 | br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "os_sensor", "base_link")); 136 | 137 | 138 | Eigen::Isometry3d odom = Eigen::Isometry3d::Identity(); 139 | odom.linear() = q_current.toRotationMatrix(); 140 | odom.translation() = t_current; 141 | 142 | Eigen::Isometry3d odomdiff = (odom_prev.inverse() * odom); 143 | q_diff = Eigen::Quaterniond(odomdiff.rotation()); 144 | t_diff = odomdiff.translation(); 145 | 146 | // Eigen::Isometry3d odom_curr = odom_prev * odomdiff; 147 | // Eigen::Quaterniond q_c = Eigen::Quaterniond(odom_curr.rotation());; 148 | // Eigen::Vector3d t_c = odom_curr.translation(); 149 | 150 | odom_prev = odom; 151 | 152 | 153 | 154 | // publish odometry 155 | nav_msgs::Odometry laserOdometry; 156 | laserOdometry.header.frame_id = "odom"; 157 | laserOdometry.child_frame_id = childframeID; 158 | laserOdometry.header.stamp = pointcloud_time; 159 | laserOdometry.pose.pose.orientation.x = q_current.x(); 160 | laserOdometry.pose.pose.orientation.y = q_current.y(); 161 | laserOdometry.pose.pose.orientation.z = q_current.z(); 162 | laserOdometry.pose.pose.orientation.w = q_current.w(); 163 | laserOdometry.pose.pose.position.x = t_current.x(); 164 | laserOdometry.pose.pose.position.y = t_current.y(); 165 | laserOdometry.pose.pose.position.z = t_current.z(); 166 | 167 | nav_msgs::Odometry odomDiff; 168 | odomDiff.header.frame_id = "odom"; 169 | odomDiff.child_frame_id = childframeID; 170 | odomDiff.header.stamp = pointcloud_time; 171 | odomDiff.pose.pose.orientation.x = q_diff.x(); 172 | odomDiff.pose.pose.orientation.y = q_diff.y(); 173 | odomDiff.pose.pose.orientation.z = q_diff.z(); 174 | odomDiff.pose.pose.orientation.w = q_diff.w(); 175 | odomDiff.pose.pose.position.x = t_diff.x(); 176 | odomDiff.pose.pose.position.y = t_diff.y(); 177 | odomDiff.pose.pose.position.z = t_diff.z(); 178 | 179 | 180 | 181 | for(int i = 0; i<36; i++) { 182 | if(i == 0 || i == 7 || i == 14) { 183 | laserOdometry.pose.covariance[i] = .01; 184 | } 185 | else if (i == 21 || i == 28 || i== 35) { 186 | laserOdometry.pose.covariance[i] += 0.1; 187 | } 188 | else { 189 | laserOdometry.pose.covariance[i] = 0; 190 | } 191 | } 192 | 193 | pubLaserOdometry.publish(laserOdometry); 194 | pubOdometryDiff.publish(odomDiff); 195 | 196 | //publish time 197 | 198 | std_msgs::Float64 time_msg; 199 | time_msg.data = time_delay*1000.0; 200 | time_average.publish(time_msg); 201 | 202 | } 203 | 204 | std::chrono::milliseconds dura(2); 205 | std::this_thread::sleep_for(dura); 206 | } 207 | } 208 | 209 | int main(int argc, char **argv) 210 | { 211 | ros::init(argc, argv, "main"); 212 | ros::NodeHandle nh; 213 | 214 | int scan_line = 16; 215 | double scan_period= 0.1; 216 | double vertical_angle = 0.0; 217 | double max_dis = 60.0; 218 | double min_dis =0; 219 | double edge_resolution = 0.3; 220 | double surf_resolution = 0.6; 221 | bool validation_angle = false; 222 | 223 | clear_map = true; 224 | cropBox_len = 10000; 225 | 226 | nh.getParam("/scan_period", scan_period); 227 | nh.getParam("/vertical_angle", vertical_angle); 228 | nh.getParam("/max_dis", max_dis); 229 | nh.getParam("/min_dis", min_dis); 230 | nh.getParam("/scan_line", scan_line); 231 | nh.getParam("/edge_resolution", edge_resolution); 232 | nh.getParam("/surf_resolution", surf_resolution); 233 | nh.getParam("/clear_map", clear_map); 234 | 235 | nh.getParam("/cropBox_len", cropBox_len); 236 | 237 | nh.getParam("/childframeID",childframeID); 238 | nh.getParam("/pcl_edge",edge_pcl); 239 | nh.getParam("/pcl_surf",surf_pcl); 240 | 241 | lidar_param.setScanPeriod(scan_period); 242 | lidar_param.setValidationAngle(validation_angle); 243 | lidar_param.setVerticalAngle(vertical_angle); 244 | lidar_param.setLines(scan_line); 245 | lidar_param.setMaxDistance(max_dis); 246 | lidar_param.setMinDistance(min_dis); 247 | 248 | odomEstimation.init(lidar_param, edge_resolution, surf_resolution); 249 | 250 | ros::Subscriber subEdgeLaserCloud = nh.subscribe(edge_pcl, 100, velodyneEdgeHandler); 251 | ros::Subscriber subSurfLaserCloud = nh.subscribe(surf_pcl, 100, velodyneSurfHandler); 252 | 253 | pubLaserOdometry = nh.advertise("/odom", 100); 254 | pubOdometryDiff = nh.advertise("/odom_diff", 100); 255 | time_average = nh.advertise("/time_average", 100); 256 | 257 | 258 | std::thread odom_estimation_process{odom_estimation}; 259 | 260 | ros::spin(); 261 | 262 | return 0; 263 | } 264 | 265 | -------------------------------------------------------------------------------- /dualquat_LOAM/rviz/kitti_displayed_std.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 0 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: ~ 7 | Splitter Ratio: 0.6264705657958984 8 | Tree Height: 892 9 | - Class: rviz/Selection 10 | Name: Selection 11 | - Class: rviz/Tool Properties 12 | Expanded: 13 | - /2D Pose Estimate1 14 | - /2D Nav Goal1 15 | - /Publish Point1 16 | Name: Tool Properties 17 | Splitter Ratio: 0.5886790156364441 18 | - Class: rviz/Views 19 | Expanded: 20 | - /Current View1 21 | Name: Views 22 | Splitter Ratio: 0.5 23 | - Class: rviz/Time 24 | Name: Time 25 | SyncMode: 0 26 | SyncSource: fullmap 27 | Preferences: 28 | PromptSaveOnExit: true 29 | Toolbars: 30 | toolButtonStyle: 2 31 | Visualization Manager: 32 | Class: "" 33 | Displays: 34 | - Alpha: 0.5 35 | Cell Size: 1 36 | Class: rviz/Grid 37 | Color: 160; 160; 164 38 | Enabled: false 39 | Line Style: 40 | Line Width: 0.029999999329447746 41 | Value: Lines 42 | Name: Grid 43 | Normal Cell Count: 0 44 | Offset: 45 | X: 0 46 | Y: 0 47 | Z: 0 48 | Plane: XY 49 | Plane Cell Count: 200 50 | Reference Frame: 51 | Value: false 52 | - Alpha: 1 53 | Class: rviz/Axes 54 | Enabled: true 55 | Length: 2 56 | Name: Axes 57 | Radius: 0.5 58 | Reference Frame: 59 | Show Trail: true 60 | Value: true 61 | - Alpha: 1 62 | Class: rviz/Axes 63 | Enabled: true 64 | Length: 2 65 | Name: Velodyne 66 | Radius: 0.5 67 | Reference Frame: velodyne 68 | Show Trail: false 69 | Value: true 70 | - Alpha: 0.5 71 | Autocompute Intensity Bounds: true 72 | Autocompute Value Bounds: 73 | Max Value: -33.894691467285156 74 | Min Value: -121.7796630859375 75 | Value: true 76 | Axis: Y 77 | Channel Name: intensity 78 | Class: rviz/PointCloud2 79 | Color: 255; 255; 255 80 | Color Transformer: Intensity 81 | Decay Time: 1000 82 | Enabled: true 83 | Invert Rainbow: true 84 | Max Color: 255; 255; 255 85 | Min Color: 0; 0; 0 86 | Name: fullmap 87 | Position Transformer: XYZ 88 | Queue Size: 10 89 | Selectable: true 90 | Size (Pixels): 1 91 | Size (m): 0.05000000074505806 92 | Style: Flat Squares 93 | Topic: /output_cloud 94 | Unreliable: false 95 | Use Fixed Frame: true 96 | Use rainbow: true 97 | Value: true 98 | - Alpha: 1 99 | Buffer Length: 1 100 | Class: rviz/Path 101 | Color: 25; 255; 0 102 | Enabled: true 103 | Head Diameter: 0.30000001192092896 104 | Head Length: 0.5 105 | Length: 0.5 106 | Line Style: Lines 107 | Line Width: 5 108 | Name: DualQuat-path 109 | Offset: 110 | X: 0 111 | Y: 0 112 | Z: 0 113 | Pose Color: 25; 255; 255 114 | Pose Style: Axes 115 | Queue Size: 10 116 | Radius: 0.20000000298023224 117 | Shaft Diameter: 0.25 118 | Shaft Length: 0.5 119 | Topic: /dualquat_odom/trajectory 120 | Unreliable: false 121 | Value: true 122 | - Class: rviz/Group 123 | Displays: 124 | - Alpha: 1 125 | Arrow Length: 0.30000001192092896 126 | Axes Length: 0.4000000059604645 127 | Axes Radius: 0.10000000149011612 128 | Class: rviz/PoseArray 129 | Color: 255; 25; 0 130 | Enabled: true 131 | Head Length: 0.07000000029802322 132 | Head Radius: 0.029999999329447746 133 | Name: STD_prev_poses 134 | Queue Size: 10 135 | Shaft Length: 0.23000000417232513 136 | Shaft Radius: 0.009999999776482582 137 | Shape: Axes 138 | Topic: /std_prev_poses 139 | Unreliable: false 140 | Value: true 141 | - Alpha: 1 142 | Arrow Length: 0.30000001192092896 143 | Axes Length: 0.4000000059604645 144 | Axes Radius: 0.10000000149011612 145 | Class: rviz/PoseArray 146 | Color: 255; 25; 0 147 | Enabled: true 148 | Head Length: 0.07000000029802322 149 | Head Radius: 0.029999999329447746 150 | Name: STD_curr_poses 151 | Queue Size: 10 152 | Shaft Length: 0.23000000417232513 153 | Shaft Radius: 0.009999999776482582 154 | Shape: Axes 155 | Topic: /std_curr_poses 156 | Unreliable: false 157 | Value: true 158 | - Alpha: 0.5 159 | Autocompute Intensity Bounds: true 160 | Autocompute Value Bounds: 161 | Max Value: 10 162 | Min Value: -10 163 | Value: true 164 | Axis: Z 165 | Channel Name: intensity 166 | Class: rviz/PointCloud2 167 | Color: 239; 41; 41 168 | Color Transformer: FlatColor 169 | Decay Time: 1000 170 | Enabled: true 171 | Invert Rainbow: false 172 | Max Color: 255; 255; 255 173 | Min Color: 0; 0; 0 174 | Name: STD_map_vertex 175 | Position Transformer: XYZ 176 | Queue Size: 10 177 | Selectable: true 178 | Size (Pixels): 3 179 | Size (m): 0.5 180 | Style: Flat Squares 181 | Topic: /std_prev_points 182 | Unreliable: false 183 | Use Fixed Frame: true 184 | Use rainbow: true 185 | Value: true 186 | - Alpha: 0.5 187 | Autocompute Intensity Bounds: true 188 | Autocompute Value Bounds: 189 | Max Value: 10 190 | Min Value: -10 191 | Value: true 192 | Axis: Z 193 | Channel Name: intensity 194 | Class: rviz/PointCloud2 195 | Color: 0; 0; 255 196 | Color Transformer: FlatColor 197 | Decay Time: 0 198 | Enabled: true 199 | Invert Rainbow: false 200 | Max Color: 255; 255; 255 201 | Min Color: 0; 0; 0 202 | Name: STD_curr_vertex 203 | Position Transformer: XYZ 204 | Queue Size: 10 205 | Selectable: true 206 | Size (Pixels): 3 207 | Size (m): 0.800000011920929 208 | Style: Flat Squares 209 | Topic: /std_curr_points 210 | Unreliable: false 211 | Use Fixed Frame: true 212 | Use rainbow: true 213 | Value: true 214 | - Class: rviz/MarkerArray 215 | Enabled: true 216 | Marker Topic: /pair_std 217 | Name: Match_arrows 218 | Namespaces: 219 | {} 220 | Queue Size: 100 221 | Value: true 222 | - Class: rviz/MarkerArray 223 | Enabled: true 224 | Marker Topic: /std_curr 225 | Name: STD_curr_triangle 226 | Namespaces: 227 | {} 228 | Queue Size: 100 229 | Value: true 230 | - Class: rviz/MarkerArray 231 | Enabled: true 232 | Marker Topic: /std_map 233 | Name: STD_map 234 | Namespaces: 235 | {} 236 | Queue Size: 100 237 | Value: true 238 | Enabled: true 239 | Name: STD 240 | Enabled: true 241 | Global Options: 242 | Background Color: 255; 255; 255 243 | Default Light: true 244 | Fixed Frame: map 245 | Frame Rate: 10 246 | Name: root 247 | Tools: 248 | - Class: rviz/Interact 249 | Hide Inactive Objects: true 250 | - Class: rviz/MoveCamera 251 | - Class: rviz/Select 252 | - Class: rviz/FocusCamera 253 | - Class: rviz/Measure 254 | - Class: rviz/SetInitialPose 255 | Theta std deviation: 0.2617993950843811 256 | Topic: /initialpose 257 | X std deviation: 0.5 258 | Y std deviation: 0.5 259 | - Class: rviz/SetGoal 260 | Topic: /move_base_simple/goal 261 | - Class: rviz/PublishPoint 262 | Single click: true 263 | Topic: /clicked_point 264 | Value: true 265 | Views: 266 | Current: 267 | Class: rviz/Orbit 268 | Distance: 89.17073059082031 269 | Enable Stereo Rendering: 270 | Stereo Eye Separation: 0.05999999865889549 271 | Stereo Focal Distance: 1 272 | Swap Stereo Eyes: false 273 | Value: false 274 | Field of View: 0.7853981852531433 275 | Focal Point: 276 | X: -5.617822647094727 277 | Y: 1.075937271118164 278 | Z: -4.993391036987305 279 | Focal Shape Fixed Size: true 280 | Focal Shape Size: 0.05000000074505806 281 | Invert Z Axis: false 282 | Name: Current View 283 | Near Clip Distance: 0.009999999776482582 284 | Pitch: 1.5697963237762451 285 | Target Frame: velodyne 286 | Yaw: 3.273189067840576 287 | Saved: ~ 288 | Window Geometry: 289 | Displays: 290 | collapsed: true 291 | Height: 1043 292 | Hide Left Dock: true 293 | Hide Right Dock: true 294 | QMainWindow State: 000000ff00000000fd000000040000000000000186000003b9fc020000000efb000000100044006900730070006c006100790073000000003d000003b9000000c900fffffffb0000000a0049006d00610067006500000002a7000001330000000000000000fb0000001200530065006c0065006300740069006f006e000000003b000000f30000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000abfb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d006100670065000000033e0000020c0000000000000000fb0000000a0049006d00610067006500000002ec000000ec0000000000000000fb0000000a0049006d006100670065000000003d000002010000000000000000fb0000000a0049006d0061006700650000000212000001c80000000000000000fb0000000a0049006d00610067006500000003d50000002100000000000000000000000100000152000003b9fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d000003b9000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000738000000a9fc0100000005fb0000000a0049006d0061006700650000000000000007380000000000000000fb0000000c00430061006d0065007200610000000000000007380000000000000000fb0000000c00430061006d0065007200610000000000000007380000000000000000fc000000000000041a0000000000fffffffa000000000200000002fb0000000a0049006d0061006700650000000000ffffffff0000000000000000fb0000000a0049006d006100670065000000003d000000a90000000000000000fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073d00000039fc0100000002fb0000000800540069006d006500000000000000073d000003bc00fffffffb0000000800540069006d0065010000000000000450000000000000000000000738000003b900000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 295 | Selection: 296 | collapsed: false 297 | Time: 298 | collapsed: false 299 | Tool Properties: 300 | collapsed: false 301 | Views: 302 | collapsed: true 303 | Width: 1848 304 | X: 1992 305 | Y: 0 306 | -------------------------------------------------------------------------------- /dualquat_LOAM/rviz/heliPR_displayed_std.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 0 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /fullmap1 9 | - /STD1/STD_map_vertex1 10 | Splitter Ratio: 0.592783510684967 11 | Tree Height: 871 12 | - Class: rviz/Selection 13 | Name: Selection 14 | - Class: rviz/Tool Properties 15 | Expanded: 16 | - /2D Pose Estimate1 17 | - /2D Nav Goal1 18 | - /Publish Point1 19 | Name: Tool Properties 20 | Splitter Ratio: 0.5886790156364441 21 | - Class: rviz/Views 22 | Expanded: 23 | - /Current View1 24 | Name: Views 25 | Splitter Ratio: 0.5 26 | - Class: rviz/Time 27 | Name: Time 28 | SyncMode: 0 29 | SyncSource: "" 30 | Preferences: 31 | PromptSaveOnExit: true 32 | Toolbars: 33 | toolButtonStyle: 2 34 | Visualization Manager: 35 | Class: "" 36 | Displays: 37 | - Alpha: 0.5 38 | Cell Size: 1 39 | Class: rviz/Grid 40 | Color: 160; 160; 164 41 | Enabled: false 42 | Line Style: 43 | Line Width: 0.029999999329447746 44 | Value: Lines 45 | Name: Grid 46 | Normal Cell Count: 0 47 | Offset: 48 | X: 0 49 | Y: 0 50 | Z: 0 51 | Plane: XY 52 | Plane Cell Count: 200 53 | Reference Frame: 54 | Value: false 55 | - Alpha: 1 56 | Class: rviz/Axes 57 | Enabled: true 58 | Length: 2 59 | Name: Axes 60 | Radius: 0.5 61 | Reference Frame: 62 | Show Trail: true 63 | Value: true 64 | - Alpha: 1 65 | Class: rviz/Axes 66 | Enabled: true 67 | Length: 2 68 | Name: Velodyne 69 | Radius: 0.5 70 | Reference Frame: ouster 71 | Show Trail: false 72 | Value: true 73 | - Alpha: 0.25 74 | Autocompute Intensity Bounds: false 75 | Autocompute Value Bounds: 76 | Max Value: 317.9651184082031 77 | Min Value: -441.6699523925781 78 | Value: true 79 | Axis: Y 80 | Channel Name: intensity 81 | Class: rviz/PointCloud2 82 | Color: 255; 255; 255 83 | Color Transformer: Intensity 84 | Decay Time: 200 85 | Enabled: true 86 | Invert Rainbow: false 87 | Max Color: 255; 255; 255 88 | Max Intensity: 128 89 | Min Color: 0; 0; 0 90 | Min Intensity: 0 91 | Name: fullmap 92 | Position Transformer: XYZ 93 | Queue Size: 10 94 | Selectable: true 95 | Size (Pixels): 1 96 | Size (m): 0.05000000074505806 97 | Style: Points 98 | Topic: /output_cloud 99 | Unreliable: false 100 | Use Fixed Frame: true 101 | Use rainbow: false 102 | Value: true 103 | - Alpha: 1 104 | Buffer Length: 1 105 | Class: rviz/Path 106 | Color: 25; 255; 0 107 | Enabled: true 108 | Head Diameter: 0.30000001192092896 109 | Head Length: 0.5 110 | Length: 0.5 111 | Line Style: Lines 112 | Line Width: 5 113 | Name: DualQuat-path 114 | Offset: 115 | X: 0 116 | Y: 0 117 | Z: 0 118 | Pose Color: 25; 255; 255 119 | Pose Style: Axes 120 | Queue Size: 10 121 | Radius: 0.20000000298023224 122 | Shaft Diameter: 0.25 123 | Shaft Length: 0.5 124 | Topic: /dualquat_odom/trajectory 125 | Unreliable: false 126 | Value: true 127 | - Class: rviz/Group 128 | Displays: 129 | - Alpha: 1 130 | Arrow Length: 0.30000001192092896 131 | Axes Length: 0.4000000059604645 132 | Axes Radius: 0.10000000149011612 133 | Class: rviz/PoseArray 134 | Color: 255; 25; 0 135 | Enabled: false 136 | Head Length: 0.07000000029802322 137 | Head Radius: 0.029999999329447746 138 | Name: STD_prev_poses 139 | Queue Size: 10 140 | Shaft Length: 0.23000000417232513 141 | Shaft Radius: 0.009999999776482582 142 | Shape: Axes 143 | Topic: /std_prev_poses 144 | Unreliable: false 145 | Value: false 146 | - Alpha: 1 147 | Arrow Length: 0.30000001192092896 148 | Axes Length: 0.4000000059604645 149 | Axes Radius: 0.10000000149011612 150 | Class: rviz/PoseArray 151 | Color: 255; 25; 0 152 | Enabled: false 153 | Head Length: 0.07000000029802322 154 | Head Radius: 0.029999999329447746 155 | Name: STD_curr_poses 156 | Queue Size: 10 157 | Shaft Length: 0.23000000417232513 158 | Shaft Radius: 0.009999999776482582 159 | Shape: Axes 160 | Topic: /std_curr_poses 161 | Unreliable: false 162 | Value: false 163 | - Alpha: 0.5 164 | Autocompute Intensity Bounds: true 165 | Autocompute Value Bounds: 166 | Max Value: 10 167 | Min Value: -10 168 | Value: true 169 | Axis: Z 170 | Channel Name: intensity 171 | Class: rviz/PointCloud2 172 | Color: 239; 41; 41 173 | Color Transformer: FlatColor 174 | Decay Time: 10 175 | Enabled: true 176 | Invert Rainbow: false 177 | Max Color: 255; 255; 255 178 | Min Color: 0; 0; 0 179 | Name: STD_map_vertex 180 | Position Transformer: XYZ 181 | Queue Size: 0 182 | Selectable: true 183 | Size (Pixels): 3 184 | Size (m): 0.5 185 | Style: Flat Squares 186 | Topic: /std_prev_points 187 | Unreliable: false 188 | Use Fixed Frame: true 189 | Use rainbow: true 190 | Value: true 191 | - Alpha: 0.5 192 | Autocompute Intensity Bounds: true 193 | Autocompute Value Bounds: 194 | Max Value: 10 195 | Min Value: -10 196 | Value: true 197 | Axis: Z 198 | Channel Name: intensity 199 | Class: rviz/PointCloud2 200 | Color: 0; 0; 255 201 | Color Transformer: FlatColor 202 | Decay Time: 0 203 | Enabled: true 204 | Invert Rainbow: false 205 | Max Color: 255; 255; 255 206 | Min Color: 0; 0; 0 207 | Name: STD_curr_vertex 208 | Position Transformer: XYZ 209 | Queue Size: 10 210 | Selectable: true 211 | Size (Pixels): 3 212 | Size (m): 0.800000011920929 213 | Style: Flat Squares 214 | Topic: /std_curr_points 215 | Unreliable: false 216 | Use Fixed Frame: true 217 | Use rainbow: true 218 | Value: true 219 | - Class: rviz/MarkerArray 220 | Enabled: true 221 | Marker Topic: /pair_std 222 | Name: Match_arrows 223 | Namespaces: 224 | {} 225 | Queue Size: 100 226 | Value: true 227 | - Class: rviz/MarkerArray 228 | Enabled: true 229 | Marker Topic: /std_curr 230 | Name: STD_curr_triangle 231 | Namespaces: 232 | {} 233 | Queue Size: 100 234 | Value: true 235 | - Class: rviz/MarkerArray 236 | Enabled: true 237 | Marker Topic: /std_map 238 | Name: STD_map 239 | Namespaces: 240 | {} 241 | Queue Size: 100 242 | Value: true 243 | Enabled: true 244 | Name: STD 245 | Enabled: true 246 | Global Options: 247 | Background Color: 255; 255; 255 248 | Default Light: true 249 | Fixed Frame: map 250 | Frame Rate: 10 251 | Name: root 252 | Tools: 253 | - Class: rviz/Interact 254 | Hide Inactive Objects: true 255 | - Class: rviz/MoveCamera 256 | - Class: rviz/Select 257 | - Class: rviz/FocusCamera 258 | - Class: rviz/Measure 259 | - Class: rviz/SetInitialPose 260 | Theta std deviation: 0.2617993950843811 261 | Topic: /initialpose 262 | X std deviation: 0.5 263 | Y std deviation: 0.5 264 | - Class: rviz/SetGoal 265 | Topic: /move_base_simple/goal 266 | - Class: rviz/PublishPoint 267 | Single click: true 268 | Topic: /clicked_point 269 | Value: true 270 | Views: 271 | Current: 272 | Class: rviz/XYOrbit 273 | Distance: 94.81476593017578 274 | Enable Stereo Rendering: 275 | Stereo Eye Separation: 0.05999999865889549 276 | Stereo Focal Distance: 1 277 | Swap Stereo Eyes: false 278 | Value: false 279 | Field of View: 0.7853981852531433 280 | Focal Point: 281 | X: 52.96240234375 282 | Y: 2.1747148036956787 283 | Z: 3.391419886611402e-05 284 | Focal Shape Fixed Size: true 285 | Focal Shape Size: 0.05000000074505806 286 | Invert Z Axis: false 287 | Name: Current View 288 | Near Clip Distance: 0.009999999776482582 289 | Pitch: 0.8442506790161133 290 | Target Frame: ouster 291 | Yaw: 6.281044006347656 292 | Saved: ~ 293 | Window Geometry: 294 | Displays: 295 | collapsed: false 296 | Height: 1016 297 | Hide Left Dock: false 298 | Hide Right Dock: false 299 | QMainWindow State: 000000ff00000000fd000000040000000000000186000003a2fc020000000efb000000100044006900730070006c006100790073010000003b000003a2000000c700fffffffb0000000a0049006d00610067006500000002a7000001330000000000000000fb0000001200530065006c0065006300740069006f006e000000003b000000f30000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000abfb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d006100670065000000033e0000020c0000000000000000fb0000000a0049006d00610067006500000002ec000000ec0000000000000000fb0000000a0049006d006100670065000000003d000002010000000000000000fb0000000a0049006d0061006700650000000212000001c80000000000000000fb0000000a0049006d00610067006500000003d50000002100000000000000000000000100000152000003a2fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b000003a2000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000738000000a9fc0100000005fb0000000a0049006d0061006700650000000000000007380000000000000000fb0000000c00430061006d0065007200610000000000000007380000000000000000fb0000000c00430061006d0065007200610000000000000007380000000000000000fc000000000000041a0000000000fffffffa000000000200000002fb0000000a0049006d0061006700650000000000ffffffff0000000000000000fb0000000a0049006d006100670065000000003d000000a90000000000000000fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073d00000039fc0100000002fb0000000800540069006d006500000000000000073d0000035c00fffffffb0000000800540069006d006501000000000000045000000000000000000000049c000003a200000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 300 | Selection: 301 | collapsed: false 302 | Time: 303 | collapsed: false 304 | Tool Properties: 305 | collapsed: false 306 | Views: 307 | collapsed: false 308 | Width: 1920 309 | X: 0 310 | Y: 27 311 | --------------------------------------------------------------------------------