Blogger Information
Blog 291
fans 0
comment 0
visits 350749
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
ROS2中使用Gtes示例
Original
1218 people have browsed it

阿里云官方镜像站:ROS2
https://developer.aliyun.com/mirror/?utm_content=g_1000303593

一、准备工作

创建工作空间,即编写代码的位置mkdir -p dev_ws/src

进入 dev_ws/src 路径下:

先创建依赖包 tutorial_interfaces:

  1. ros2 pkg create --build-type ament_cmake tutorial_interfaces

进入 dev_ws/src/tutorial_interfaces ,然后创建msg和srv目录存放.msg文件和.srv文件:

  1. mkdir msg
  2. mkdir srv

进入dev_ws/src/tutorial_interface/msg目录,新建 Num.msg文件:

  1. int64 num

进入 dev_ws/src/tutorial_interface/srv目录,新建 AddThreeInts.srv文件:

  1. int64 a
  2. int64 b
  3. int64 c
  4. ---
  5. int64 sum

然后编辑CMakeLists.txt文件:

  1. find_package(rosidl_default_generators REQUIRED)
  2. rosidl_generate_interfaces(${PROJECT_NAME}
  3. "msg/Num.msg"
  4. "srv/AddThreeInts.srv"
  5. )

继续编辑package.xml:

  1. <build_depend>rosidl_default_generators</build_depend>
  2. <exec_depend>rosidl_default_runtime</exec_depend>
  3. <member_of_group>rosidl_interface_packages</member_of_group>

最后回到工作空间路径下编译构建 tutorial_interfaces 包:

  1. colcon build --packages-select tutorial_interfaces

以上操作步骤详细链接:

Creating custom ROS 2 msg and srv files — ROS 2 Documentation: Galactic documentation

然后在工作空间的src路径下创建自己的包 service,并指定依赖的包:

  1. ros2 pkg create --build-type ament_cmake service --dependencies rclcpp tutorial_interfaces

在 dev_ws/src/service/src目录下新建service.cpp

  1. #include "rclcpp/rclcpp.hpp"
  2. #include "tutorial_interfaces/srv/add_three_ints.hpp" // CHANGE
  3. #include <memory>
  4. void add(const std::shared_ptr<tutorial_interfaces::srv::AddThreeInts::Request> request, // CHANGE
  5. std::shared_ptr<tutorial_interfaces::srv::AddThreeInts::Response> response) // CHANGE
  6. {
  7. response->sum = request->a + request->b + request->c; // CHANGE
  8. RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld" " c: %ld", // CHANGE
  9. request->a, request->b, request->c); // CHANGE
  10. RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum);
  11. }
  12. int main(int argc, char **argv)
  13. {
  14. rclcpp::init(argc, argv);
  15. std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_three_ints_server"); // CHANGE
  16. rclcpp::Service<tutorial_interfaces::srv::AddThreeInts>::SharedPtr service = // CHANGE
  17. node->create_service<tutorial_interfaces::srv::AddThreeInts>("add_three_ints", &add); // CHANGE
  18. RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add three ints."); // CHANGE
  19. rclcpp::spin(node);
  20. rclcpp::shutdown();
  21. }

二、测试代码编写

进入工作空间的src路径下,执行下面命令生成待测模块client:

  1. ros2 pkg create --build-type ament_cmake client --dependencies rclcpp tutorial_interfaces

进入client路径下,分别新建src,test目录,include目录默认已经存在。

include目录下文件:client.h和params.h

  1. // client.h
  2. #ifndef CLIENT_H
  3. #define CLIENT_H
  4. class ClientHandler
  5. {
  6. public:
  7. ClientHandler();
  8. ~ClientHandler();
  9. bool sendParams(int argc, char **argv);
  10. };
  11. #endif
  1. // params.h
  2. #ifndef PARAMS_H
  3. #define PARAMS_H
  4. extern int my_argc;
  5. extern char** my_argv;
  6. #endif

src目录下文件:client.cpp和main.cpp

  1. // client.cpp
  2. #include "rclcpp/rclcpp.hpp"
  3. #include "tutorial_interfaces/srv/add_three_ints.hpp"
  4. #include "../include/client.h"
  5. #include <chrono>
  6. #include <cstdlib>
  7. #include <memory>
  8. #include<vector>
  9. using namespace std;
  10. using namespace std::chrono_literals;
  11. // 构造函数
  12. ClientHandler::ClientHandler(){
  13. }
  14. // 析构函数
  15. ClientHandler::~ClientHandler(){
  16. }
  17. // 普通函数——发送参数
  18. bool ClientHandler::sendParams(int argc, char **argv)
  19. {
  20. rclcpp::init(argc, argv);
  21. if (argc != 4) {
  22. RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "usage: add_three_ints_client X Y Z");
  23. return false;
  24. }
  25. std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_three_ints_client");
  26. rclcpp::Client<tutorial_interfaces::srv::AddThreeInts>::SharedPtr client =
  27. node->create_client<tutorial_interfaces::srv::AddThreeInts>("add_three_ints");
  28. auto request = std::make_shared<tutorial_interfaces::srv::AddThreeInts::Request>();
  29. request->a = atoll(argv[1]);
  30. request->b = atoll(argv[2]);
  31. request->c = atoll(argv[3]);
  32. while (!client->wait_for_service(1s)) {
  33. if (!rclcpp::ok()) {
  34. RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting.");
  35. return false;
  36. }
  37. RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again...");
  38. }
  39. auto result = client->async_send_request(request);
  40. // Wait for the result.
  41. if (rclcpp::spin_until_future_complete(node, result) ==
  42. rclcpp::FutureReturnCode::SUCCESS)
  43. {
  44. RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sum: %ld", result.get()->sum);
  45. } else {
  46. RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service add_three_ints");
  47. }
  48. rclcpp::shutdown();
  49. return true;
  50. }
  1. // main.cpp
  2. #include "../include/client.h"
  3. int main(int argc, char **argv){
  4. // 注意这里: C++ 编译器把不带参数的构造函数优先认为是一个函数声明
  5. ClientHandler client{};
  6. client.sendParams(argc, argv);
  7. }

test目录下文件:clientTest.cpp和main.cpp

  1. // clientTest.cpp
  2. #include "gtest/gtest.h"
  3. #include "../include/client.h"
  4. #include "../include/params.h"
  5. TEST(ClientHandler, sendParams)
  6. {
  7. // 测试的时候的交互方式也不能改变,既然client实际的效果是在命令行输入参数,
  8. // 那这里也是这样的效果
  9. ClientHandler client{};
  10. EXPECT_EQ(true, client.sendParams(my_argc, my_argv));
  11. }
  1. // main.cpp
  2. #include <gtest/gtest.h>
  3. // #include <gmock/gmock.h>
  4. int my_argc;
  5. char** my_argv;
  6. int main(int argc, char** argv) {
  7. // ::testing::InitGoogleMock(&argc, argv);
  8. // 注意这里使用的是Gtest,不是Gmock
  9. ::testing::InitGoogleTest(&argc, argv);
  10. // Runs all tests using Google Test.
  11. my_argc = argc;
  12. my_argv = argv;
  13. return RUN_ALL_TESTS();
  14. }

CMakeLists.txt文件:

  1. cmake_minimum_required(VERSION 3.8)
  2. project(client)
  3. if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  4. add_compile_options(-Wall -Wextra -Wpedantic)
  5. endif()
  6. # find dependencies
  7. find_package(ament_cmake REQUIRED)
  8. find_package(rclcpp REQUIRED)
  9. find_package(tutorial_interfaces REQUIRED)
  10. set(SRC
  11. src/client.cpp
  12. src/main.cpp
  13. )
  14. add_executable(client
  15. ${SRC}
  16. )
  17. ament_target_dependencies(client
  18. rclcpp tutorial_interfaces)
  19. # 5. 添加当前项目中的头文件 注意有顺序的要求,不能乱
  20. target_include_directories(client
  21. PRIVATE
  22. ${PROJECT_SOURCE_DIR}/include
  23. )
  24. # 如果是测试代码
  25. if(BUILD_TESTING)
  26. find_package(ament_lint_auto REQUIRED)
  27. # 加入gtest包
  28. find_package(ament_cmake_gtest REQUIRED)
  29. # the following line skips the linter which checks for copyrights
  30. # uncomment the line when a copyright and license is not present in all source files
  31. # set(ament_cmake_copyright_FOUND TRUE)
  32. # the following line skips cpplint (only works in a git repo)
  33. # uncomment the line when this package is not in a git repo
  34. # set(ament_cmake_cpplint_FOUND TRUE)
  35. set(TEST
  36. test/main.cpp
  37. test/clientTest.cpp
  38. )
  39. # 生成加入gtest的test执行文件。${PROJECT_NAME}_test为自定义的test执行文件名称;test/demo_test.cpp为test源码路径
  40. # 注意这里导包的时候,不再需要将 .h 文件导入进来,因为在 client.cpp中已经导入了我们需要使用到的.h文件
  41. # 另外,注意这里不能导入开发代码中的 main.cpp,因为已经有了一个测试的main.cpp
  42. ament_add_gtest(${PROJECT_NAME}_test ${TEST} src/client.cpp)
  43. # 务必注意这里需要添加的依赖包
  44. ament_target_dependencies(${PROJECT_NAME}_test rclcpp tutorial_interfaces)
  45. install(TARGETS
  46. ${PROJECT_NAME}_test
  47. # 将生成的test执行文件安装到DESTINATION后的路径下
  48. DESTINATION lib/${PROJECT_NAME})
  49. ament_lint_auto_find_test_dependencies()
  50. endif()
  51. install(TARGETS
  52. client
  53. DESTINATION lib/${PROJECT_NAME})
  54. # 设置编译构建类型为 调试 模式
  55. set(CMAKE_BUILD_TYPE Debug)
  56. # 生成覆盖率文件
  57. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
  58. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage")
  59. ament_package()

package.xml文件:

  1. <?xml version="1.0"?>
  2. <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
  3. <package format="3">
  4. <name>client</name>
  5. <version>0.0.0</version>
  6. <description>TODO: Package description</description>
  7. <maintainer email="zhi@todo.todo">zhi</maintainer>
  8. <license>TODO: License declaration</license>
  9. <buildtool_depend>ament_cmake</buildtool_depend>
  10. <depend>rclcpp</depend>
  11. <depend>tutorial_interfaces</depend>
  12. <test_depend>ament_lint_auto</test_depend>
  13. <test_depend>ament_lint_common</test_depend>
  14. <export>
  15. <build_type>ament_cmake</build_type>
  16. </export>
  17. </package>

然后回到工作空间执行编译构建命令:

  1. colcon build --packages-select client

进入到 dev_ws/build/client路径下,找到client_test可执行文件即为生成的测试文件

在另外一个终端启动service包:

  1. ros2 run cpp_srvcli server

执行

  1. ./client_test 23 3 4

运行测试文件即可。

生成覆盖率的脚本:

  1. #!/usr/bin/bash
  2. echo "begin gen coverage file ..."
  3. lcov --no-external --capture --initial --directory . --output-file /home/zhi/ros2-gtest-gmock/info/ros2_base.info
  4. cd /home/zhi/ros2-gtest-gmock/build/client;./client_test 45 56 56;cd /home/zhi/ros2-gtest-gmock
  5. # 注意下面的=号两侧是不可以有空格的,这是个大坑
  6. current_path=$(pwd)
  7. echo "当前目录是:" $current_path
  8. lcov --no-external --capture --directory . --output-file /home/zhi/ros2-gtest-gmock/info/ros2.info
  9. lcov --add-tracefile /home/zhi/ros2-gtest-gmock/info/ros2_base.info --add-tracefile /home/zhi/ros2-gtest-gmock/info/ros2.info --output-file /home/zhi/ros2-gtest-gmock/info/ros2_coverage.info
  10. mkdir -p coverage && genhtml /home/zhi/ros2-gtest-gmock/info/ros2_coverage.info --output-directory coverage

程序封装改写:

如果不知道返回类型,直接断点下去看下类型:

本文转自:https://www.cnblogs.com/huaibin/p/15423963.html

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post