准备
1.下载好g2o的代码。下载地址:https://github.com/RainerKuemmerle/g2o
如果只是在Ubuntu系统上安装g2o,可以参考代码库中的readme.md。
2.下载suitesparse4.4.6. 选择4.4.6版本是因为我发现ROS系统中使用的是这个版本。即使用sudo apt-get install libsuitesparse-dev命令安装的版本。
3.相应的编译工具make 和cmake 是要有的。
4.安装自己的交叉编译工具链。我这里使用的是arm板厂商提供的编译工具。
对G2O库的改造
1.将suitesparse文件夹中的CXSParse里的源码替换掉g2o的EXTERNAL文件夹中的csparse。
注意SuiteSparse_config文件夹中的SuiteSparse_config.h也需要拷过去。
EXTERNAL中的CMakeList.txt里59行需要去掉cs_api.h。因为这个文件已经没有了。
以上步骤主要是将g2o中原来的csparse替换为性能更好的cxsparse。
2.修改g2o的CMakeList.txt。
1)按照下面的方式设置交叉编译工具。
SET(CMAKE_SYSTEM_NAME Linux)
SET(TOOLCHAIN_DIR "/home/andrew/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu")
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/aarch64-linux-gnu-g++)
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/aarch64-linux-gnu-gcc)
SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR} ${TOOLCHAIN_DIR}/aarch64-linux-gnu/include ${TOOLCHAIN_DIR}/aarch64-linux-gnu/lib)
2)关掉了CHOLMOD,因为我没有使用CHOLMOD的solver。
# For building the CHOLMOD / CSPARSE solvers
option (G2O_USE_CHOLMOD "Build g2o with CHOLMOD support" OFF)
3)使g2o自己编译EXTERNAL中的csparse。
# find_package(CSparse)
# if (G2O_USE_CSPARSE)
# if(CSPARSE_FOUND)
# set(BUILD_CSPARSE OFF CACHE BOOL "Build local CSparse library")
# else(CSPARSE_FOUND)
set(BUILD_CSPARSE ON CACHE BOOL "Build local CSparse library")
if(BUILD_CSPARSE)
set(CSPARSE_FOUND TRUE)
endif()
# endif(CSPARSE_FOUND)
# else(G2O_USE_CSPARSE)
# set(BUILD_CSPARSE OFF "Build local CSparse library")
# endif(G2O_USE_CSPARSE)
4)注释掉FIND_PACKAGE(OpenMP)一段
# Eigen library parallelise itself, though, presumably due to performance issues
# OPENMP is experimental. We experienced some slowdown with it
# set(G2O_USE_OPENMP OFF CACHE BOOL "Build g2o with OpenMP support (EXPERIMENTAL)")
# if(G2O_USE_OPENMP)
# find_package(OpenMP)
# if(OPENMP_FOUND)
# set (G2O_OPENMP 1)
# set(g2o_C_FLAGS "${g2o_C_FLAGS} ${OpenMP_C_FLAGS}")
# set(g2o_CXX_FLAGS "${g2o_CXX_FLAGS} -DEIGEN_DONT_PARALLELIZE ${OpenMP_CXX_FLAGS}")
# message(STATUS "Compiling with OpenMP support")
# endif(OPENMP_FOUND)
# endif(G2O_USE_OPENMP)
4)自己设置eigen库的头文件地址。
SET(EIGEN3_INCLUDE_DIR "/home/andrew/compile_eigen3_2/arm_eigen3/install/include/eigen3")
SET(G2O_EIGEN3_INCLUDE ${EIGEN3_INCLUDE_DIR})
5)关掉一些不要编译的东西。
关掉apps编译
# shall we build the core apps using the library
set(G2O_BUILD_APPS OFF CACHE BOOL "Build g2o apps")
关掉examples的编译
# shall we build the examples
set(G2O_BUILD_EXAMPLES OFF CACHE BOOL "Build g2o examples")
在上面的CMakeLists.txt里注释掉
# Pre-canned types
# add_subdirectory(types)
在solver文件夹里的
# add_subdirectory(pcg)
# add_subdirectory(dense)
# add_subdirectory(structure_only)
# add_subdirectory(slam2d_linear)
# add_subdirectory(eigen)
意味着我们只保留了csparse。
6)注释掉g2o根文件夹中CMakeLists.txt里的这一段
# Start of SSE* autodetect code
# (borrowed from MRPT CMake scripts, BSD)
# option(DO_SSE_AUTODETECT "Enable autodetection of SSE* CPU sets and enable their use in optimized code" ON)
# if(NOT EXISTS "/proc/cpuinfo")
# set(DO_SSE_AUTODETECT OFF)
# endif()
# if (DO_SSE_AUTODETECT)
# file(READ "/proc/cpuinfo" G2O_CPU_INFO)
# endif()
# # Macro for each SSE* var: Invoke with name in uppercase:
# macro(DEFINE_SSE_VAR _setname)
# string(TOLOWER ${_setname} _set)
# if (DO_SSE_AUTODETECT)
# # Automatic detection:
# set(CMAKE_G2O_HAS_${_setname} 0)
# if (${G2O_CPU_INFO} MATCHES ".*${_set}.*")
# set(CMAKE_G2O_HAS_${_setname} 1)
# endif()
# else (DO_SSE_AUTODETECT)
# # Manual:
# set("DISABLE_${_setname}" OFF CACHE BOOL "Forces compilation WITHOUT ${_setname} extensions")
# mark_as_advanced("DISABLE_${_setname}")
# set(CMAKE_G2O_HAS_${_setname} 0)
# if (NOT DISABLE_${_setname})
# set(CMAKE_G2O_HAS_${_setname} 1)
# endif (NOT DISABLE_${_setname})
# endif (DO_SSE_AUTODETECT)
# endmacro(DEFINE_SSE_VAR)
# # SSE optimizations:
# IF (NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
# DEFINE_SSE_VAR(SSE2)
# DEFINE_SSE_VAR(SSE3)
# DEFINE_SSE_VAR(SSE4_1)
# DEFINE_SSE_VAR(SSE4_2)
# DEFINE_SSE_VAR(SSE4_A)
# ENDIF()
编译
在g2o根文件夹下执行下面的命令。
mkdir build && cd build
cmake ..
make
编译完后,库会放在lib文件夹下。
使用g2o时只需链接g2o_ext_csparse g2o_core g2o_csparse_extension g2o_stuff这几个库。
g2o的使用注意事项
1.新下载的g2o代码与之前的老版本有点差异。主要是solver的定义方式有区别。需要按照下面的方法更改。
// TEBLinearSolver* linearSolver = new TEBLinearSolver(); // see typedef in optimization.h
// linearSolver->setBlockOrdering(true);
// TEBBlockSolver* blockSolver = new TEBBlockSolver(linearSolver);
// g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(blockSolver);
//需要用unique
auto linearSolver = g2o::make_unique<TEBLinearSolver>();
linearSolver->setBlockOrdering(true);
g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(
g2o::make_unique<TEBBlockSolver>(std::move(linearSolver)));
2.头文件引用
需要引用g2o的文件和csparse的头文件。
include_directories(/home/kevin/Downloads/g2o_arm)
include_directories(/home/kevin/Downloads/g2o_arm/EXTERNAL)
关注公众号《首飞》回复“机器人”获取精心推荐的C/C++,Python,Docker,Qt,ROS1/2等机器人行业常用技术资料。