之前分两篇文章介绍了CV开发的常用开发库及其头文件。详见《CV学习日志:CV开发之常用库及其头文件》和《CV学习日志:CV开发之ROS2和Webots头文件及其自动提取》。
本篇给出基于CV开发常用库的CMake配置模板,并给出使用了ROS2的样例。
给出的CMake配置基于ubuntu20.04,开发库除Webots(Webots采用默认安装路径)外都是通过apt-get安装,详见《CV学习日志:CV开发之Ubuntu2004和WLS2环境搭建》。
给出的CMake工程假设了一个自定义库,即基于ROS2自编译的库,colon编译安装路径是/root/app/ros2ex/out/install。
以下是CMake模板的详细代码,尤其要注意配置了Threads和对QT5添加了特殊配置。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 ###I.Global#################################################################### 2 cmake_minimum_required(VERSION 3.5) 3 project(aaron) 4 set(CMAKE_CXX_STANDARD 14) 5 set(CMAKE_CXX_STANDARD_REQUIRED True) 6 set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/out) 7 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/out) 8 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/header) #if header directory exists 9 10 ###II.UNIX#################################################################### 11 if(UNIX) 12 set(THREADS_PREFER_PTHREAD_FLAG ON) 13 find_package(Threads REQUIRED) 14 message("Platform: UNIX Platform: UNIX Platform: UNIX Platform: UNIX Platform: UNIX Platform: UNIX ") 15 16 #1.Qt5 17 include_directories(/usr/include/x86_64-linux-gnu/qt5) 18 file(GLOB Qt5_LIBS /usr/lib/x86_64-linux-gnu/libQt5*.so.5) #remove Qt5Bootstrap and Qt5Debug if they exist 19 add_compile_definitions(QT_WIDGETS_LIB) #Add QT_NO_VERSION_TAGGING if installing Qt manually 20 add_compile_options(-fPIC) 21 22 #2.OpenCV 23 include_directories(/usr/include/opencv4) 24 file(GLOB OpenCV_LIBS /usr/lib/x86_64-linux-gnu/libopencv*.so) 25 26 #3.Eigen3 Gflags Glog Ceres Spdlog 27 include_directories(/usr/include) 28 include_directories(/usr/include/eigen3) 29 file(GLOB Gflags_LIBS /usr/lib/x86_64-linux-gnu/libgflags*.so) 30 file(GLOB Glog_LIBS /usr/lib/x86_64-linux-gnu/libglog*.so) 31 file(GLOB Ceres_LIBS /usr/lib/libceres*.so) 32 33 #4.ROS2 ROS2EX Webots 34 include_directories(/opt/ros/foxy/include /root/app/ros2ex/out/install/include) 35 include_directories(/usr/local/webots/include/controller/cpp /usr/local/webots/include/controller/c) 36 file(GLOB ROS2_LIBS LIST_DIRECTORIES false /opt/ros/foxy/lib/*.so) 37 file(GLOB ROS2EX_LIBS LIST_DIRECTORIES false /root/app/ros2ex/out/install/lib/*.so) 38 file(GLOB Webots_LIBS LIST_DIRECTORIES false /usr/local/webots/lib/controller/*.so) 39 40 #5.Octomap 41 include_directories(/usr/include) 42 file(GLOB Octomap_LIBS /usr/lib/x86_64-linux-gnu/liboctom*.so)#octomap&octomath 43 set(Octomap_LIBS ${Octomap_LIBS} /usr/lib/x86_64-linux-gnu/liboctovis.so) 44 set(Octomap_LIBS ${Octomap_LIBS} /usr/lib/x86_64-linux-gnu/libdynamicedt3d.so) 45 46 #8.AllLibs 47 set(ALL_LIBS ${Qt5_LIBS} ${OpenCV_LIBS} ${ROS2_LIBS} ${ROS2EX_LIBS} ${Webots_LIBS} 48 ${Gflags_LIBS} ${Glog_LIBS} ${Ceres_LIBS} ${Octomap_LIBS}) 49 link_libraries(${ALL_LIBS}) 50 message("ALL_LIBS: ${ALL_LIBS}") 51 52 ###9.2ROSTest 53 set(rostestcpp ${CMAKE_SOURCE_DIR}/rostest.cpp) 54 add_executable(rostest ${rostestcpp}) 55 target_link_libraries(rostest Threads::Threads) 56 endif(UNIX)
以下是ROS2使用样例的详细代码,依赖于C++14、OpenCV4.x、Spdlog及Foxy。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "cvheaders.h" //write this file based on previous articles 2 3 #ifndef ns1970 4 #define ms1970 chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()).time_since_epoch().count() 5 #define us1970 chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now()).time_since_epoch().count() 6 #define ns1970 chrono::time_point_cast<chrono::nanoseconds>(chrono::system_clock::now()).time_since_epoch().count() 7 #endif 8 9 class RosTestCore 10 { 11 public: 12 static void AirRobot(int argc = 0, char **argv = 0) 13 { 14 //0.InitROS 15 rclcpp::init(argc, argv); 16 17 //1.PreROS 18 int64 nPubFrame = 0; 19 rclcpp::Node::SharedPtr nodAirRobot = rclcpp::Node::make_shared("airRobot", "acv"); 20 rclcpp::Publisher<ssrmsg::Image>::SharedPtr pubRawFrame = nodAirRobot->create_publisher<ssrmsg::Image>("rawFrame", 2); 21 rclcpp::TimerBase::SharedPtr TimerTimestamp = nodAirRobot->create_wall_timer(200ms, [&]()->void 22 { 23 //1.PrepareData 24 int64 ts = ns1970; 25 ssrmsg::Image::UniquePtr ima = make_unique<ssrmsg::Image>(); 26 ima->header.frame_id = std::to_string(++nPubFrame); 27 ima->header.stamp.sec = ts / 1000000000; 28 ima->header.stamp.nanosec = ts % 1000000000; 29 ima->width = 640; 30 ima->height = 480; 31 ima->step = 3 * ima->width; 32 ima->is_bigendian = 0; 33 ima->encoding = CV_8UC3; 34 ima->data.assign(ima->step * ima->height, 128); 35 cv::putText(Mat_<Vec3b>(ima->height, ima->width, (Vec3b*)ima->data.data()), ima->header.frame_id, Point(300, 220), FONT_HERSHEY_PLAIN, 4, Scalar(255, 0, 0), 4); 36 37 //2.PublishData 38 pubRawFrame->publish(std::move(ima)); 39 40 //3.PrintDetails 41 spdlog::info("nPubFrame: {}", nPubFrame); 42 spdlog::info(" Node::get_name: {}", nodAirRobot->get_name()); 43 spdlog::info(" Node::get_namespace: {}", nodAirRobot->get_namespace()); 44 spdlog::info(" Node::get_sub_namespace: {}", nodAirRobot->get_sub_namespace()); 45 spdlog::info(" Node::get_effective_namespace: {}", nodAirRobot->get_effective_namespace()); 46 spdlog::info(" Node::get_fully_qualified_name: {}", nodAirRobot->get_fully_qualified_name()); 47 }); 48 49 //2.SpinROS 50 rclcpp::spin(nodAirRobot); 51 52 //3.StopROS 53 rclcpp::shutdown(); 54 } 55 56 public: 57 static void LandRobot(int argc = 0, char **argv = 0) 58 { 59 //0.InitROS 60 rclcpp::init(argc, argv); 61 62 //1.PreROS 63 int64 nSubRawFrame = 0; 64 rclcpp::Node::SharedPtr nodLandRobot = rclcpp::Node::make_shared("landRobot", "acv"); 65 rclcpp::Subscription<ssrmsg::Image>::SharedPtr subRawFrame = nodLandRobot->create_subscription<ssrmsg::Image>("rawFrame", 2, [&](ssrmsg::Image::UniquePtr frame) 66 { 67 cv::imshow("RawFrame", Mat_<Vec3b>(frame->height, frame->width, (Vec3b*)frame->data.data())); 68 cv::waitKey(10); 69 spdlog::info("nSubRawFrame: {}", ++nSubRawFrame); 70 spdlog::info(" Node::get_name: {}", nodLandRobot->get_name()); 71 spdlog::info(" Node::get_namespace: {}", nodLandRobot->get_namespace()); 72 spdlog::info(" Node::get_sub_namespace: {}", nodLandRobot->get_sub_namespace()); 73 spdlog::info(" Node::get_effective_namespace: {}", nodLandRobot->get_effective_namespace()); 74 spdlog::info(" Node::get_fully_qualified_name: {}", nodLandRobot->get_fully_qualified_name()); 75 }); 76 77 //2.SpinROS 78 rclcpp::spin(nodLandRobot); 79 80 //3.StopROS 81 rclcpp::shutdown(); 82 } 83 }; 84 85 int main(int argc, char** argv) 86 { 87 if (argc < 2){ spdlog::critical("appName nodeName(airRobot/landRobot)"); return -1; } 88 89 if (strcmp(argv[1], "airRobot") == 0) RosTestCore::AirRobot(argc, argv); 90 else if (strcmp(argv[1], "landRobot") == 0) RosTestCore::LandRobot(argc, argv); 91 92 return 0; 93 }
打开两个终端执行source /opt/ros/foxy/setup.bash后,再分别执行以下命令可查看效果。
1)终端一:./rostest airRobot
2)终端二:./rostest landRobot