创建ROS-wrapper

2023-05-16

创建ROS-wrapper

  • 对高博的ygz-stereo-inertial的开源算法添加ROS node
    • 源文件的编写
    • CMakeLists文件的编写
      • 分目录下的CMakeLists
        • 完整CMakeLists
          • 路径/home/fei/devv/ygz-stereo-inertial-master/backend下的CMakeLists文件
          • 路径/home/fei/devv/ygz-stereo-inertial-master/common下的CMakeLists文件
          • 路径 /home/fei/devv/ygz-stereo-inertial-master/cv下的完整CMakeLists
          • 路径/home/fei/devv/ygz-stereo-inertial-master/system下的CMakeLists
          • 路径/home/fei/devv/ygz-stereo-inertial-master/util下的CMakeLists
        • 小结
      • 在主目录下的CMakeLists
        • 完整的CMakeLists文件
      • ROS目录下的CMakeLists
        • 完整CMakeLists

ros节点是为了让整个工程能够订阅topic消息,那么必须要给这个工程创建一个ros node ,以便能够通过ROS来进行控制,对于部分的开源算法,可能不会提供ROS Wrapper功能包,那么这需要自己写一个才能成功运用于ROS工程并能落地实现。

对高博的ygz-stereo-inertial的开源算法添加ROS node

这里也并不知道为什么源码不提供ROS接口,而只是单纯的跑跑数据集。但是最后发现自己写出来的ROS node照样是跑.bag数据集文件效果并不是很好。

源文件的编写

1、基本格式

  ros::init(argc,argv,"ygz_ros");
  ros::start();
  ros::NodeHandle nh;

这是必不可少的语句,其中ygz_ros是当前节点的名称,并且是当前工程下唯一的。

  • 函数原型:ros::init(argc, argv, “my_node_name”, ros::init_options::AnonymousName);
  • 初始化节点名字必须在最前面,如果ROS系统中出现重名,则之前的节点会被自动关闭
  • 如果想要多个重名节点而不报错,可以在init中添加ros::init_options::AnonymousName参数
  • 该参数会在原有节点名字的后面添加一些随机数来使每个节点独一无二
  • ros::NodeHandle获取节点的句柄,init是初始化节点,ros::start()是Starting the node
  • 如果不想通过对象的生命周期来管理节点的开始和结束,
  • 你可以通过ros::start()和ros::shutdown() 来自己管理节点。

2、订阅图像topic消息

    message_filters::Subscriber<sensor_msgs::Image> left_sub(nh, left_topic, 2);
    message_filters::Subscriber<sensor_msgs::Image> right_sub(nh, right_topic, 2);
    

这两句是分别创建了订阅left_topic、right_topic两个topic消息的对象,最后一个参数是缓冲容器,如果缓冲容器中已满,那么如再有topic消息进来,那么会丢弃前面的topic。具体参考官网

    typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::Image, sensor_msgs::Image> sync_pol;
    message_filters::Synchronizer<sync_pol> sync(sync_pol(10), left_sub,right_sub);
    sync.registerCallback(boost::bind(&ImageGrabber::FetchImageCallback,&igb,_1,_2));

那么需要对订阅的两个topic被一个回调函数进行处理,需要进行以上的编写,其中boost::bind(&ImageGrabber::FetchImageCallback,&igb,_1,_2)是回调函数。可参考

其中这里的boost::bind的调用,目的是使用一个类的成员函数作为回调函数所必须的操作。这里,boost::bind中的第一个参

数是回调函数名,第二个是回调函数所属类的对象,第三个 _1 是一个占位符,因为回调函数image_callback的第一个参数

是msg,要给它留位置。第四个,就是传的一个参数。以此扩展,如果想要传两个参数,和留多一个占用符,那么这

样:boost::bind(image_callback, _1, _2,&pub_vt, &pub_odo),不要把_1/_2当做参数个数哈
3、订阅IMU topic消息

    ros::Subscriber imu_sub = nh.subscribe(imu_topic, 10, &ImageGrabber::FetchImuCallback, &igb);
  • 由于IMU只有一个topic,因此不需要像订阅图像topic一样创建各种对象。这里直接可以用subscribe函数进行订阅且执行回调函数。
  • 同样是使用类中的成员函数作为回调函数,但是这里并没有调用boost::bind。这是区别,应该注意

4、ros::spin()
在最后要加上ros::spin()
在topic接收方,有一个比较重要的概念,就是回调(CallBack),在本例中,回调就是预先给话题传来的消息准备一个回调函数,你事先定义好回调函数的操作,这里分别是对图像和IMU数据进行处理。只有当有消息来时,回调函数才会被触发执行。具体去触发的命令就是 ros::spin() ,它会反复的查看有没有消息来,如果有就会让回调函数去处理。
因此千万不要认为,只要指定了回调函数,系统就回去自动触发,你必须 ros::spin() 或者 ros::spinOnce() 才能真正使回调函数生效。
5、源文件

#include <math.h>
#include <Eigen/Core>

#include <opencv2/opencv.hpp>
#include <opencv2/core/eigen.hpp>

#include "ygz/System.h"   //../../../system/include
#include "ygz/EurocReader.h"  //../../../util/include/

#include <ros/ros.h>
#include <sensor_msgs/Imu.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/NavSatFix.h>
#include <geometry_msgs/QuaternionStamped.h> //for DJI.



#include <cv_bridge/cv_bridge.h>
#include <message_filters/subscriber.h>
#include <message_filters/time_synchronizer.h>
#include <message_filters/sync_policies/approximate_time.h>


#include <geometry_msgs/PoseStamped.h> //for px4's external pose estimate


using namespace std;
using namespace ygz;
using namespace cv;

class ImageGrabber
{
public:
    ImageGrabber(System* pSLAM):mpSLAM(pSLAM){}


    void FetchImuCallback(const sensor_msgs::Imu& imu);
    void FetchImageCallback(const sensor_msgs::ImageConstPtr& msgLeft,const sensor_msgs::ImageConstPtr& msgRight);
    
    System* mpSLAM;
    VecIMU temp_vimu;
    //bool do_rectify;
    cv::Mat M1l,M2l,M1r,M2r;
};





int main(int argc,char **argv)
{
  //初始化节点名字必须在最前面,如果ROS系统中出现重名,则之前的节点会被自动关闭
//如果想要多个重名节点而不报错,可以在init中添加ros::init_options::AnonymousName参数
//该参数会在原有节点名字的后面添加一些随机数来使每个节点独一无二
//ros::init(argc, argv, "my_node_name", ros::init_options::AnonymousName);
  
  ros::init(argc,argv,"ygz_ros");
  ros::start();
    if(argc != 2)
    {
        cout<<"YOU NEED TO SPECIFY CONFIG PATH!"<<endl;
        return 0;
    }
   	//获取节点的句柄,init是初始化节点,这个是Starting the node
	//如果不想通过对象的生命周期来管理节点的开始和结束,
	//你可以通过ros::start()和ros::shutdown() 来自己管理节点。 
    ros::NodeHandle nh;
    
    string configFile(argv[1]);
    cv::FileStorage fsSettings(configFile, cv::FileStorage::READ);

    if (fsSettings.isOpened() == false) {
        cerr << "Cannot load the config file from " << argv[1] << endl;
    }

    System system(argv[1]);
    //pSystem = &system;
    
    ImageGrabber igb(&system);
    
    string left_topic = string(fsSettings["Left"]);
    string right_topic = string(fsSettings["Right"]);
    string imu_topic=string(fsSettings["IMU"]);
    
    // rectification parameters
    cv::Mat K_l, K_r, P_l, P_r, R_l, R_r, D_l, D_r;
    fsSettings["LEFT.K"] >> K_l;
    fsSettings["RIGHT.K"] >> K_r;

    fsSettings["LEFT.P"] >> P_l;
    fsSettings["RIGHT.P"] >> P_r;

    fsSettings["LEFT.R"] >> R_l;
    fsSettings["RIGHT.R"] >> R_r;

    fsSettings["LEFT.D"] >> D_l;
    fsSettings["RIGHT.D"] >> D_r;

    int rows_l = fsSettings["LEFT.height"];
    int cols_l = fsSettings["LEFT.width"];
    int rows_r = fsSettings["RIGHT.height"];
    int cols_r = fsSettings["RIGHT.width"];

    if (K_l.empty() || K_r.empty() || P_l.empty() || P_r.empty() || R_l.empty() || R_r.empty() || D_l.empty() ||
        D_r.empty() ||
        rows_l == 0 || rows_r == 0 || cols_l == 0 || cols_r == 0) {
        cerr << "ERROR: Calibration parameters to rectify stereo are missing!" << endl;
        return 1;
    }

    
    cv::initUndistortRectifyMap(K_l, D_l, R_l, P_l.rowRange(0, 3).colRange(0, 3), cv::Size(cols_l, rows_l), CV_32F, igb.M1l,
                                igb.M2l);
    cv::initUndistortRectifyMap(K_r, D_r, R_r, P_r.rowRange(0, 3).colRange(0, 3), cv::Size(cols_r, rows_r), CV_32F, igb.M1r,
                                igb.M2r);




	
    VecIMU vimus;
 //   if (LoadImus(imuFolder, vimus) == false)
 //       return 1;

    // read TBC
    cv::Mat Rbc, tbc;
    fsSettings["RBC"] >> Rbc;
    fsSettings["TBC"] >> tbc;
    if (!Rbc.empty() && tbc.empty()) {
        Matrix3d Rbc_;
        Vector3d tbc_;
        Rbc_ <<
             Rbc.at<double>(0, 0), Rbc.at<double>(0, 1), Rbc.at<double>(0, 2),
                Rbc.at<double>(1, 0), Rbc.at<double>(1, 1), Rbc.at<double>(1, 2),
                Rbc.at<double>(2, 0), Rbc.at<double>(2, 1), Rbc.at<double>(2, 2);
        tbc_ <<
             tbc.at<double>(0, 0), tbc.at<double>(1, 0), tbc.at<double>(2, 0);

        setting::TBC = SE3d(Rbc_, tbc_);
    }

    
    
   // ros::init(argc, argv, "ygz_ros");
  //  ros::NodeHandle nh;
        message_filters::Subscriber<sensor_msgs::Image> left_sub(nh, left_topic, 2);
    message_filters::Subscriber<sensor_msgs::Image> right_sub(nh, right_topic, 2);
    
    
    ros::Subscriber imu_sub = nh.subscribe(imu_topic, 10, &ImageGrabber::FetchImuCallback, &igb);
    


    typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::Image, sensor_msgs::Image> sync_pol;
    message_filters::Synchronizer<sync_pol> sync(sync_pol(10), left_sub,right_sub);
    sync.registerCallback(boost::bind(&ImageGrabber::FetchImageCallback,&igb,_1,_2));

    ros::spin();
    return 0;
  
}


 void ImageGrabber::FetchImuCallback(const sensor_msgs::Imu& imu)
{
  //LOG(INFO) << "fetching imu" << endl;
  IMUData t_imu(imu.angular_velocity.x,
		imu.angular_velocity.y,
		imu.angular_velocity.z,
		imu.linear_acceleration.x,
		imu.linear_acceleration.y,
		imu.linear_acceleration.z,
		imu.header.stamp.toSec() );
  cerr<<"IMU time stamp:"<<imu.header.stamp.toNSec()<<endl;
  
  temp_vimu.push_back(t_imu);
  //LOG(INFO) << "fecthing imu2" << endl;
}

void ImageGrabber::FetchImageCallback(const sensor_msgs::ImageConstPtr& msgLeft,const sensor_msgs::ImageConstPtr& msgRight)
{
    // Copy the ros image message to cv::Mat.
    cv_bridge::CvImageConstPtr cv_ptrLeft;
    try
    {
        cv_ptrLeft = cv_bridge::toCvShare(msgLeft);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }

    cv_bridge::CvImageConstPtr cv_ptrRight;
    try
    {
        cv_ptrRight = cv_bridge::toCvShare(msgRight);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }

        cv::Mat imLeft, imRight;
        cv::remap(cv_ptrLeft->image,imLeft,M1l,M2l,cv::INTER_LINEAR);
        cv::remap(cv_ptrRight->image,imRight,M1r,M2r,cv::INTER_LINEAR);
	//imLeft=cv_ptrLeft->image, imRight=cv_ptrRight->image;
	//toNSec得到的是浮点数toSec得到的是
	cerr<<"image time stamp:"<<cv_ptrLeft->header.stamp.toNSec()<<endl;
        mpSLAM->AddStereoIMU(imLeft,imRight,cv_ptrLeft->header.stamp.toSec(),temp_vimu);

    //清理上一状态的imu数据,方便接收下一批新的imu数据
    temp_vimu.clear();

}

CMakeLists文件的编写

要让上面源文件试用于该工程,那么必须对这个文件进行正确编写,这主要涉及到头文件、外部共享库等相关的调用,要能提供搜索路径
整上我是单独创建了一个ROS工作目录,在example目录下创建了ros文件夹,用于创建工作目录。类似与ORBSLAM2的ROS工作空间。

分目录下的CMakeLists

首先主目录下(/home/fei/devv/ygz-stereo-inertial-master)的CMakeLists文件是不需要进行改动的,然后为了能够让ROS工作空间中的源文件(.cpp)能够顺利使用该工程下定义的各个功能函数和类,需要给这个工程创建共享库。
路径:

  • /home/fei/devv/ygz-stereo-inertial-master/backend
  • /home/fei/devv/ygz-stereo-inertial-master/common
  • /home/fei/devv/ygz-stereo-inertial-master/cv
  • /home/fei/devv/ygz-stereo-inertial-master/system
  • /home/fei/devv/ygz-stereo-inertial-master/util
    这些文件夹下面都放置了当前工程需要用到的头文件和源文件,要单独为这些创建共享库,那么在对应路径下的CMakeLists文件下
    使用下面命令
add_library(ygz-system SHARED
        src/System.cpp
)

SHARED是生成共享库的关键字、ygz-system是该共享库的名称、 src/System.cpp只需要提供源文件。那么其它路径下同样是一样按照这种方式生成共享库

固定生成库的存放路径

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)

放在主目录下的lib文件夹下
在生成该共享库的时候,可能需要其它共享库(类似需要外部头文件一样),那么需要把一些库连接到当前生成库中

target_link_libraries( ygz-system 
    ygz-common ygz-cv ygz-util ygz-backend
)

最终在lib目录下

在这里插入图片描述为了方便能更好的连接这些库,那么把他们整合到一起,用set命令,定义一个变量。

set(YGZ_LIBS ygz-common ygz-cv ygz-util ygz-backend ygz-system)
# 同样三方库也进行整合
set(THIRD_PARTY_LIBS
        ${OpenCV_LIBS}
        ${EIGEN3_LIBS}
        ${Pangolin_LIBRARIES}
        ${PROJECT_SOURCE_DIR}/Thirdparty/DBoW2/lib/libDBoW2.so
        ${PROJECT_SOURCE_DIR}/Thirdparty/fast/build/libfast.so
        ${PROJECT_SOURCE_DIR}/Thirdparty/g2o/lib/libg2o.so
        ${BLAS_LIBRARIES}
        ${LAPACK_LIBRARIES}
        ${GLOG_LIBRARY}
)

注意这里的YGZ_LIBS和THIRD_PARTY_LIBS只适合当前工作环境内使用,不如之后的ROS工作空间下不能再使用这个变量,需要重新声明
上面的这个库只是为了能够让该工程创建的可执行文件(非ROS节点)进行共享库的链接,如路径
/home/fei/devv/ygz-stereo-inertial-master/examples下的CMakeLists

add_executable(EurocStereo EurocStereo.cpp)
target_link_libraries(EurocStereo
        ${YGZ_LIBS}
        ${THIRD_PARTY_LIBS}
        )

add_executable(EurocStereoVIO EurocStereoVIO.cpp)
target_link_libraries(EurocStereoVIO
        ${YGZ_LIBS}
        ${THIRD_PARTY_LIBS}
        )

add_executable(Kitti Kitti.cpp)
target_link_libraries(Kitti
        ${YGZ_LIBS}
        ${THIRD_PARTY_LIBS}
        )

消除XXX.c:(.text+0x12): undefined reference to `XXX’ 的未定义声明的错误

完整CMakeLists

整合后的三方库使用体现在 ygz-util 共享库的生成上

target_link_libraries( ygz-util 
        ${THIRD_PARTY_LIBS}
)
路径/home/fei/devv/ygz-stereo-inertial-master/backend下的CMakeLists文件
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)


add_library( ygz-backend SHARED
        src/BackendSlidingWindowG2O.cpp
        )

SET_TARGET_PROPERTIES(ygz-backend PROPERTIES OUTPUT_NAME "ygz-backend")
路径/home/fei/devv/ygz-stereo-inertial-master/common下的CMakeLists文件

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
add_library(ygz-common SHARED
        src/IMUData.cpp
        src/Settings.cpp
        src/Frame.cpp
        src/MapPoint.cpp
        src/G2OTypes.cpp
        )

target_link_libraries(ygz-common
        ${THIRD_PARTY_LIBS}
        )

SET_TARGET_PROPERTIES(ygz-common PROPERTIES OUTPUT_NAME "ygz-common")
路径 /home/fei/devv/ygz-stereo-inertial-master/cv下的完整CMakeLists
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
add_library(ygz-cv SHARED
        src/ORBExtractor.cpp
        src/ORBMatcher.cpp
        src/Tracker.cpp
        src/Align.cpp
        src/LKFlow.cpp
        src/TrackerLK.cpp
        )

target_link_libraries(ygz-cv ygz-common ${THIRD_PARTY_LIBS})

SET_TARGET_PROPERTIES(ygz-cv PROPERTIES OUTPUT_NAME "ygz-cv")
路径/home/fei/devv/ygz-stereo-inertial-master/system下的CMakeLists
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
add_library(ygz-system SHARED
        src/System.cpp
)

target_link_libraries( ygz-system 
    ygz-common ygz-cv ygz-util ygz-backend
)

SET_TARGET_PROPERTIES(ygz-system  PROPERTIES OUTPUT_NAME "ygz-system")
路径/home/fei/devv/ygz-stereo-inertial-master/util下的CMakeLists
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
add_library( ygz-util SHARED
        src/EurocReader.cpp
        src/Viewer.cpp
)

target_link_libraries( ygz-util 
        ${THIRD_PARTY_LIBS}
)

SET_TARGET_PROPERTIES(ygz-util  PROPERTIES OUTPUT_NAME "ygz-util")

小结

这原工程是把一些头文件和源文件进行了不同文件夹的分类,那么需要都把这些路径通过CMakeLists告诉编译器,并且在生成共享库的时候我们这里是每一个子目录下进行单独生成,其实也可以在主目录下进行共享库的生成,只不过需要给清除路径
另一种方案是把所有的头文件和源文件都放在一个子目录下(类似于ORBSLAM2工程),

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)

add_library(${PROJECT_NAME} SHARED
src/System.cc
src/Tracking.cc
src/LocalMapping.cc
src/LoopClosing.cc
src/ORBextractor.cc
src/ORBmatcher.cc
src/FrameDrawer.cc
src/Converter.cc
src/MapPoint.cc
src/KeyFrame.cc
src/Map.cc
src/MapDrawer.cc
src/Optimizer.cc
src/PnPsolver.cc
src/Frame.cc
src/KeyFrameDatabase.cc
src/Sim3Solver.cc
src/Initializer.cc
src/Viewer.cc
src/InitKeyFrame.cc
src/SystemSetting.cc
)

这样生成库的时候不需要这么麻烦,但是为了不大幅度改动原工程结构,还是保留原结构

在主目录下的CMakeLists

该目录是主要提供外部三方库的搜索路径和分布在各个文件夹内的头文件的路径,解决以下的错误提示
XXX.cpp:1:19: error: XXX.h: 没有那个文件或目录

#三方库头文件的搜索路径
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/Thirdparty/fast/include
${PROJECT_SOURCE_DIR}/Thirdparty/DBoW2
${PROJECT_SOURCE_DIR}/Thirdparty/g2o/
${EIGEN3_INCLUDE_DIR}
${Pangolin_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
)
#内部头文件路径
include_directories(
        util/include
        cv/include
        common/include
        backend/include
        system/include
)

由于工程中还有其它的文件夹,并且存放着不同的源文件和头文件且这些文件夹中也都有属于自己的CMakeLists,那么需要让它们进行相互连接一起编译,需要在主目录下的CMakeLists文件声明文件夹

add_subdirectory(util)
add_subdirectory(common)
add_subdirectory(cv)
add_subdirectory(backend)
add_subdirectory(system)
add_subdirectory( examples )

完整的CMakeLists文件

cmake_minimum_required( VERSION 2.8 )
project(YGZ-Stereo)

# uncommont this to use release
set( CMAKE_BUILD_TYPE "Release" )

# make sure we use Release and warn otherwise
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to 'Release' as none was specified.")
  set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
    "MinSizeRel" "RelWithDebInfo")
endif()


if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
  message(WARNING "CMAKE_BUILD_TYPE not set to 'Release'. Performance may be terrible.")
else()
  message(STATUS "Building with build type '${CMAKE_BUILD_TYPE}', turn on the compiler optimization")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -Wall -march=native -O3 -Wno-reorder -pthread -fopenmp")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -march=native -O3 -pthread -fopenmp")
endif()

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)

# Check C++11 or C++0x support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
   add_definitions(-DCOMPILEDWITHC11)
   message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
   add_definitions(-DCOMPILEDWITHC0X)
   message(STATUS "Using flag -std=c++0x.")
else()
   message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

# arm and intel cpu configurations
IF(DEFINED ENV{ARM_ARCHITECTURE})
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -march=armv7-a")
ELSE()
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse -msse2 -march=native")
ENDIF()

LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake-modules)

# thirdparty libs 
find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
    message(STATUS "Don't get Opencv 3.0, looking for OpenCV 2.4.")
   find_package(OpenCV 2.4 QUIET)
   if(NOT OpenCV_FOUND)
      message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
   endif()
endif()

find_package(Eigen3 3.1.0 REQUIRED)
find_package(Pangolin REQUIRED)
find_package( Glog REQUIRED )

# to show 'include' in QtCreator
FILE(GLOB_RECURSE INC_ALL "*/*.h")
add_custom_target(headers SOURCES ${INC_ALL})

include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/Thirdparty/fast/include
${PROJECT_SOURCE_DIR}/Thirdparty/DBoW2
${PROJECT_SOURCE_DIR}/Thirdparty/g2o/
${EIGEN3_INCLUDE_DIR}
${Pangolin_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
)


# thirdparty
set(THIRD_PARTY_LIBS
        ${OpenCV_LIBS}
        ${EIGEN3_LIBS}
        ${Pangolin_LIBRARIES}
        ${PROJECT_SOURCE_DIR}/Thirdparty/DBoW2/lib/libDBoW2.so
        ${PROJECT_SOURCE_DIR}/Thirdparty/fast/build/libfast.so
        ${PROJECT_SOURCE_DIR}/Thirdparty/g2o/lib/libg2o.so
        ${BLAS_LIBRARIES}
        ${LAPACK_LIBRARIES}
        ${GLOG_LIBRARY}
)

# subdirectories
include_directories(
        util/include
        cv/include
        common/include
        backend/include
        system/include
)


add_subdirectory(util)

add_subdirectory(common)

add_subdirectory(cv)

add_subdirectory(backend)

add_subdirectory(system)

set(YGZ_LIBS ygz-common ygz-cv ygz-util ygz-backend ygz-system)

# build examples
add_subdirectory( examples )

ROS目录下的CMakeLists

在ROS目录下需要配置CMakeLists文件,并且是针对ROS工程的

include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()

要在文件开头加上创建ROS空间的环境

需要为ros节点的.cpp源文件能够访问到当前工程的头文件,然后需要添加头文件搜索路径。这里解决的问题是找不到头文件的错误提示
error: xxx.h: 没有那个文件或目录

include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../../../
${PROJECT_SOURCE_DIR}/../../../include
${PROJECT_SOURCE_DIR}/../../../cv/include
${PROJECT_SOURCE_DIR}/../../../common/include
${PROJECT_SOURCE_DIR}/../../../util/include
${PROJECT_SOURCE_DIR}/../../../backend/include
${PROJECT_SOURCE_DIR}/../../../system/include
${Pangolin_INCLUDE_DIRS}
)

注意这里的${PROJECT_SOURCE_DIR}是当前CMakeLists所在的目录,是当前ROS工作空间的路径

添加上面的头文件的搜索路径的时候那么上面找不到头文件的提示已经消失了但是还是会出现另一个错误

xxx.cpp:(.text+0x12): undefined reference to `XXXX’

这需要在生成可执行文件的时候需要链接上所有需要的外部库(注意当前工程对于ROS空间来说都属于外部库),为了方便添加,我们先把所有的外部共享库整合到一个变量来表示

set(LIBS 
${OpenCV_LIBS} 
${EIGEN3_LIBS}
${Pangolin_LIBRARIES}
${PROJECT_SOURCE_DIR}/../../../Thirdparty/DBoW2/lib/libDBoW2.so
${PROJECT_SOURCE_DIR}/../../../Thirdparty/g2o/lib/libg2o.so

-lboost_system
)

set(YGZ_LIBS
${PROJECT_SOURCE_DIR}/../../../lib/libygz-backend.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-common.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-cv.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-util.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-system.so
)

这里的LIBS和YGZ_LIBS就是整合之后的外部共享库、YGZ_LIBS和之前虽然同名但是所代表的值是不一样的
通过

TARGET_LINK_LIBRARIES(target library1
<debug | optimized> library2
...)

给可执行文件链接外部共享库,如:

rosbuild_add_executable(YGZ-StereoVIO-ROS
src/eurocSteteoVIO_ros.cpp
)

target_link_libraries(YGZ-StereoVIO-ROS
${LIBS}
${YGZ_LIBS}
)

注意rosbuild_add_executable是生成ROS可执行文件的语法,和add_executable一样的使用方法
这样外部共享库链接上了可执行文件之后就会把 undefined reference to `XXXX’ 这错误给消除

完整CMakeLists

cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)

rosbuild_init()

IF(NOT ROS_BUILD_TYPE)
  SET(ROS_BUILD_TYPE Release)
ENDIF()

MESSAGE("Build type: " ${ROS_BUILD_TYPE})

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  -Wall  -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall  -O3 -march=native")

# Check C++11 or C++0x support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
   add_definitions(-DCOMPILEDWITHC11)
   message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
   add_definitions(-DCOMPILEDWITHC0X)
   message(STATUS "Using flag -std=c++0x.")
else()
   message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../../cmake_modules)

find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
   find_package(OpenCV 2.4.3 QUIET)
   if(NOT OpenCV_FOUND)
      message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
   endif()
endif()

find_package(Eigen3  REQUIRED)
find_package(Pangolin REQUIRED)

include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../../../
${PROJECT_SOURCE_DIR}/../../../include
${PROJECT_SOURCE_DIR}/../../../cv/include
${PROJECT_SOURCE_DIR}/../../../common/include
${PROJECT_SOURCE_DIR}/../../../util/include
${PROJECT_SOURCE_DIR}/../../../backend/include
${PROJECT_SOURCE_DIR}/../../../system/include
${Pangolin_INCLUDE_DIRS}
)

set(LIBS 
${OpenCV_LIBS} 
${EIGEN3_LIBS}
${Pangolin_LIBRARIES}
${PROJECT_SOURCE_DIR}/../../../Thirdparty/DBoW2/lib/libDBoW2.so
${PROJECT_SOURCE_DIR}/../../../Thirdparty/g2o/lib/libg2o.so
-lboost_system
)

set(YGZ_LIBS
${PROJECT_SOURCE_DIR}/../../../lib/libygz-backend.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-common.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-cv.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-util.so
${PROJECT_SOURCE_DIR}/../../../lib/libygz-system.so
)
# Node for monocular camera
rosbuild_add_executable(YGZ-StereoVIO-ROS
src/eurocSteteoVIO_ros.cpp
)

target_link_libraries(YGZ-StereoVIO-ROS
${LIBS}
${YGZ_LIBS}
)

rosbuild_add_executable(YGZ-Stereo-ROS
src/eurocSteteoVIO_ros.cpp
)

target_link_libraries(YGZ-Stereo-ROS
${LIBS}
${YGZ_LIBS}
)



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建ROS-wrapper 的相关文章

  • catkin_make后找不到ROS包

    我根据 ROS 的 Wiki 页面创建了一个 ROS 工作区 我还使用创建了一个包catkin create pkg在我刚刚创建的工作区下 然后 按照 ROS Wiki 中的步骤使用以下命令构建包catkin make 构建包后 我插入命令
  • 当 SocketChannel 关闭时如何得到通知?

    我希望在以下情况时收到通知SocketChannel http docs oracle com javase 7 docs api java nio channels SocketChannel html有它的close http docs
  • 包装一个对象

    我有一个对象 它有一堆公共属性 没有 getter 和 setter 坏的 因此 我创建了一个包含属性的类 并为它们创建了 getter 和 setter 我的计划是将对象包装在我的类中 因此这意味着不能直接访问属性 我有点不确定该怎么做
  • 如何使用 Cython 将 python 函数作为参数传递给 c++ 函数

    这是我的设置 我有下一个要包装的 C 类 Foo h class Foo public typedef int MyType typedef int ArgType1 typedef int ArgType2 typedef MyType
  • 如何在 C++/CLI 中包装 C 库回调

    给定以下具有要求设置缓冲区的回调事件的 C 库 如何以类型安全的方式编写正确的 C CLI 包装器 The callback signature typedef void cdecl BUFFERALLOCATOR void opaque
  • 安装 GDL 以在 Python 中使用

    我需要使用一些GDL http gnudatalanguage sourceforge net credits php我的 Python 代码中的例程 In the GitHub 仓库 https github com cenit GDL
  • jQuery 用 div 包裹多个 id

    我试图用 div 包装选定的 id 集 并用不同的 id 包装其他集 但不太确定它应该如何工作 我有以下 html 代码 div class wrapper div div class post div div div div class
  • 如果包装器使用拆箱,那么 intValue() 方法需要什么?

    例如 看看这段代码 Integer myInt new Integer 5 int i1 myInt intValue int i2 myInt System out println i1 System out println i2 正如您
  • 自定义 Cython 生成的 .so 文件的位置

    我有一个 Cython 包 其中包含 C 库的包装器 这是包的树形结构 package api pxd wrap pyx setup py wrapper init py wrap py Doing python setup py buil
  • 容器和包装的区别

    在编程语言 例如 Java 中 有什么区别container and wrapper 或者有什么区别 我听过这两个术语的使用都很模糊 在编程语言中这个词容器通常用于可以包含多个元素的结构 例如Map a Set or a List 这些结构
  • 使用 ctypes 从 python 调用 C 函数

    我有以下 C 代码 我正在尝试使用Python从Python调用这个函数ctypes int add int arr printf number d n arr 0 arr 0 1 return arr 0 我用以下方法编译了这个 gcc
  • C# InputSimulator 包装器 - 如何使用它?

    我想模拟外部程序的键盘点击 我尝试过SendMessage PostMessage SendKeys 但它们不会将密钥发送到某个特定程序 所以我想尝试 SendInput 并且我已经下载了一个很好的包装器发送输入 http msdn mic
  • Windows 在 PATH 中搜索可执行文件的相对顺序是什么?

    如果我有a com a cmd a bat and a exe我的文件中的 PATH 如果我只调用该命令 Windows 会选择哪一个a 这是微软官方指定的吗 我只是想包裹我的gvim exe可执行文件 n 但是我的gvim bat似乎既不
  • 所有原始包装类都是不可变对象吗?

    Java 中的所有原始包装类都是不可变对象吗 字符串是不可变的 其他不可变对象是什么 Any type which doesn t give you any means to change the data within it is imm
  • 从实例驻留在固定格式(数据库、MMF)的基类派生...如何安全?

    Note 我正在寻找有关正确搜索词的任何建议来阅读此类问题 对象关系映射 http en wikipedia org wiki Object relational mapping我想到了一个可以找到一些好的现有技术的地方 但我还没有看到任何
  • 最近用 Java 编写的 FFTW 包装器

    我正在寻找最新版本的最小 Java 包装器FFTW http www fftw org FFTW 网站上列出的包装器要么已过时 jfftw 1 2 zip ftp ftp fftw org pub fftw jfftw 1 2 zip 或包
  • C# 数据库包装设计

    我正在为 C 设计一个数据库包装器 以下是我有两个选择 选项A class DBWrapper IDisposable private SqlConnection sqlConn public DBWrapper sqlConn new S
  • 如何使用一个凉亭同时创建两个地图?

    如下图所示 现在我的gazebo正在运行2个slam gmapping包 首先是 turtlebot slam gmapping 发布到 map 主题 第二个是 slam gmapping 发布到与第一个相同的 map 主题 我想创建一个新
  • 安装 ROS 时 Cmake 未检测到 boost-python

    我一直在尝试在我的 Mac 上安装 ROS 并根据不同版本的 boost 使用不同的库解决了错误 然而 似乎有一个库甚至没有检测到 boost python 这是我得到的错误 CMake Error at usr local share c
  • 一次分配多个字段的聪明方法?

    由于遗留函数调用 我有时被迫编写像这样的丑陋的包装器 function return someWrapper someField a someField a b someField b and so on realistically it

随机推荐

  • Hadoop权威指南

    1 Hadoop基础知识 第1章 初识Hadoop Hadoop代替配有大量硬盘的数据库来进行大规模数据分析的原因是 xff1a 传输速率 xff08 取决于硬盘的带宽 xff09 的提升远大于寻址时间 xff08 将磁头移动到特定硬盘位置
  • 创建新分支,拉取代码

    1 查看当前已存在分支 git branch 2 创建新的分支 创建一个dev分支 git checkout b dev 3 提交分支到远程仓库 git push origin dev 4 删除本地分支 git branch D dev
  • 操作系统之什么是中断?

    什么是中断 xff1f 在学习操作系统中 xff0c 经常性的会看到中断这个概念 xff0c 最典型的就是汇编代码中的int命令 用一个比较通俗的概念来说 xff0c 就是计算机会连接许多外接设备 xff0c 包括磁盘 显示器 键盘鼠标等等
  • 树莓派断网自动重连WiFi

    树莓派WiFi有时候信号不好会断 xff0c 并不会自动重新连网 解决办法是 xff1a 写一个自动断网重连的脚本 xff0c 让pi定时执行并检查网络是否连通 xff0c 如断网则自动重新连接 连接还是失败 xff0c 重启 1 xff0
  • Flask 中使用 AJAX 异步加载 Bootstrap 表格(Tables)

    Flask 中使用 AJAX 异步加载 Bootstrap 表格 Tables 1 快速安装 2 一步一步做 3 概述 4 项目结构 4 1 Python 部分 app py 4 2 HTML 部分 index html 4 3 Styli
  • OpenMV超声波测距

    OpenMV超声波测距 本文首发于 xff1a https www bilibili com read cv3051569 参考链接 xff1a https blog csdn net bei dai he article details
  • Git常用命令pull、push、fetch

    pull pull意为拉 xff0c 这里引申为拉取代码 在Git命令中使用pull xff0c 会将你的远程代码拉取到本地并进行合并 格式 xff1a git pull lt 远程主机名 gt lt 远程分支名 gt lt 本地分支名 g
  • Ubuntu系统man命令中文汉化

    1 下载中文包 进入 opt xff0c 使用管理权限下载 xff1a wget https src fedoraproject org repo pkgs man pages zh CN manpages zh 1 5 1 tar gz
  • 文末彩蛋 | 这个 Request URL 长得好不一样

    有朋友拿到一个网站请求的链接问这要怎么解密 xff1f 很明显这不是加密的数据 xff0c 这是一张图片 base64 后的结果 xff0c 第一次写爬虫朋友遇到这样的请求 xff0c 可能需要琢磨一下这是什么东西 如果有遇到类似数据 xf
  • Redis(十) 布隆过滤器

    速记 为什么使用布隆过滤器 xff1f 1 为了省内存 xff0c 提高速率 2 因为1所以布隆过滤器不需要百分百正确 3 说存在不一定存在 xff0c 说不存在一定不存在 4 在解决缓存穿透的问题时 xff0c 拦截了大部分的请求 xff
  • 第五章:数学运算-statistics:统计计算-平均值

    5 5 statistics 统计计算 statistics模块实现常用的统计公式 xff0c 允许使用python的各种数值类型 xff08 int float xff0c Decimal和Fraction 来完成高效计算 5 5 1 平
  • 用proxychains4解决rosdep init问题教程

    在终端下载源码 sudo git clone https github com rofl0r proxychains ng git 进入安装目录 cd proxychains ng 配置 configure prefix 61 usr sy
  • 使用 TX2 和 realsense D435i 相机运行 ORBSLAM3

    非 ROS 版本 之后可能会更新 ROS 版本的 ORBSLAM3 配置指南 TODO 目录 TX2 刷机JetPack 4 6 1安装 realsense SDK 2 0编译 opencv 4 5 0编译 Pangolin 0 5编译运行
  • 解决 cv_bridge 与 opencv4 版本冲突问题

    解决了在 ROS melodic noetic 下 cv bridge 与 opencv4 版本冲突导致的 opencv 操作 导致 Segmentation fault core dumped 的问题 目录 问题描述解决方法参考 问题描述
  • 我对onSizeChange方法的源码解析

    如果当前的自定义控件是继承ViewGroup xff0c 那么在ViewGroup重写的layout方法中 xff1a 可知调用父类也就是View的layout方法 再看View的layout方法 xff1a 查看设置自己坐标的setFra
  • 5 个你不知道的关于 Python 类的技巧

    5 个你不知道的关于 Python 类的技巧 1 创建 一个 常量值2 多个类构造函数3 创建枚举4 迭代器5 以列表的形式访问一个类 Python 有许多强大的特性 xff0c 在处理类时提供了极大的灵活性 在这里 xff0c 我将向您展
  • 激光雷达和RTK的标定(无人小车)

    总结一下最近的标定工作 xff0c 标定平台是实验室的无人小车 xff0c 目标是实现激光雷达 lidar 和RTK的标定 xff0c 也就是求解lidar到RTK的位姿变换矩阵 采用的代码是ETH的lidar align https gi
  • 虚拟机安装Ubuntu20.04 + VCS2018

    虚拟机安装Ubuntu20 04 43 VCS2018 前言正文1 准备内容Vmware Workstation 16 prounbuntu 20 04 安装包vcs 43 scl 43 verdi等安装包 2 Ubuntu系统的安装ope
  • input里面file实现上传图片及预览功能

    在这里插入简单的HTML代码片 lt form action 61 34 34 gt 文件 xff1a lt input type 61 34 file 34 name 61 34 myFile 34 id 61 34 myFile 34
  • 创建ROS-wrapper

    创建ROS wrapper 对高博的ygz stereo inertial的开源算法添加ROS node源文件的编写CMakeLists文件的编写分目录下的CMakeLists完整CMakeLists路径 home fei devv ygz