Ali Cloud official mirror station: ROS2 source

Developer.aliyun.com/mirror/?utm…

First, preparation

Create the workspace, the place to write the code mkdir -p dev_ws/ SRC

Go to the dev_ws/ SRC path:

Tutorial_interfaces:

ros2 pkg create --build-type ament_cmake tutorial_interfaces
Copy the code

Go to dev_ws/ SRC /tutorial_interfaces and create MSG and SRV directories to store. MSG and. SRV files:

mkdir msg

mkdir srv
Copy the code

Go to dev_ws/ SRC /tutorial_interface/ MSG and create Num. MSG file:

int64 num
Copy the code

Go to dev_ws/ SRC /tutorial_interface/ SRV and create the addthreets. SRV file:

int64 a
int64 b
int64 c
---
int64 sum
Copy the code

Then edit the cmakelists.txt file:

find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/Num.msg"
  "srv/AddThreeInts.srv"
 )
Copy the code

Continue editing package.xml:

<build_depend>rosidl_default_generators</build_depend>

<exec_depend>rosidl_default_runtime</exec_depend>

<member_of_group>rosidl_interface_packages</member_of_group>
Copy the code

Tutorial_interfaces:

colcon build --packages-select tutorial_interfaces
Copy the code

Detailed links of the above operation steps:

Creating Custom ROS 2 MSG and SRV files — ROS 2 Documentation: Galactic Documentation

Then create your own package service under the SRC path of the workspace and specify the dependent package:

ros2 pkg create --build-type ament_cmake service --dependencies rclcpp tutorial_interfaces
Copy the code

Create service. CPP in the dev_ws/ SRC /service/ SRC directory

#include "rclcpp/rclcpp.hpp"
#include "tutorial_interfaces/srv/add_three_ints.hpp"                                        // CHANGE

#include <memory>

void add(const std::shared_ptr<tutorial_interfaces::srv::AddThreeInts::Request> request,     // CHANGE
          std::shared_ptr<tutorial_interfaces::srv::AddThreeInts::Response>       response)  // CHANGE
{
  response->sum = request->a + request->b + request->c;                                      // CHANGE
  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld" " c: %ld",  // CHANGE
                request->a, request->b, request->c);                                         // CHANGE
  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum);
}

int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);

  std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_three_ints_server");   // CHANGE

  rclcpp::Service<tutorial_interfaces::srv::AddThreeInts>::SharedPtr service =               // CHANGE
    node->create_service<tutorial_interfaces::srv::AddThreeInts>("add_three_ints",  &add);   // CHANGE

  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add three ints.");                     // CHANGE

  rclcpp::spin(node);
  rclcpp::shutdown();
}
Copy the code

Second, test code writing

Go to the SRC path of the workspace and run the following command to generate the client module to be tested:

ros2 pkg create --build-type ament_cmake client --dependencies rclcpp tutorial_interfaces
Copy the code

In the client path, create the SRC, test, and include directories. By default, these directories already exist.

H and params.h files in the include directory

// client.h
#ifndef CLIENT_H
#define CLIENT_H

class ClientHandler
{
    public:
        ClientHandler();
        ~ClientHandler();
        bool sendParams(int argc, char **argv);
};
#endif
Copy the code
// params.h
#ifndef PARAMS_H
#define PARAMS_H

extern int my_argc;
extern char** my_argv;

#endif
Copy the code

Files in the SRC directory: client. CPP and main. CPP

// client.cpp #include "rclcpp/rclcpp.hpp" #include "tutorial_interfaces/srv/add_three_ints.hpp" #include ".. /include/client.h" #include <chrono> #include <cstdlib> #include <memory> #include<vector> using namespace std; using namespace std::chrono_literals; / / constructor ClientHandler: : ClientHandler () {} / / destructors ClientHandler: : ~ ClientHandler ordinary function () {} / / - bool send parameters ClientHandler::sendParams(int argc, char **argv) { rclcpp::init(argc, argv); if (argc ! = 4) { RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "usage: add_three_ints_client X Y Z"); return false; } std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_three_ints_client"); rclcpp::Client<tutorial_interfaces::srv::AddThreeInts>::SharedPtr client = node->create_client<tutorial_interfaces::srv::AddThreeInts>("add_three_ints"); auto request = std::make_shared<tutorial_interfaces::srv::AddThreeInts::Request>(); request->a = atoll(argv[1]); request->b = atoll(argv[2]); request->c = atoll(argv[3]); while (! client->wait_for_service(1s)) { if (! rclcpp::ok()) { RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting."); return false; } RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again..." ); } auto result = client->async_send_request(request); // Wait for the result. if (rclcpp::spin_until_future_complete(node, result) == rclcpp::FutureReturnCode::SUCCESS) { RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sum: %ld", result.get()->sum); } else { RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service add_three_ints"); } rclcpp::shutdown(); return true; }Copy the code
// main.cpp #include ".. /include/client.h" int main(int argc, char **argv){ client.sendParams(argc, argv); }Copy the code

The files in the test directory are clienttest. CPP and main. CPP

// clientTest.cpp #include "gtest/gtest.h" #include ".. /include/client.h" #include ".. /include/params.h" TEST(ClientHandler, sendParams) {include/params.h" TEST(ClientHandler, sendParams) Since the actual effect of client is to enter arguments on the command line, // this is also the effect of ClientHandler client{}; EXPECT_EQ(true, client.sendParams(my_argc, my_argv)); }Copy the code
// main.cpp #include <gtest/gtest.h> // #include <gmock/gmock.h> int my_argc; char** my_argv; int main(int argc, char** argv) { // ::testing::InitGoogleMock(&argc, argv); / / note here use Gtest, not Gmock: : testing: : InitGoogleTest (& arg c, argv); // Runs all tests using Google Test. my_argc = argc; my_argv = argv; return RUN_ALL_TESTS(); }Copy the code

CMakeLists. TXT file:

Cmake_minimum_required (VERSION 3.8) project(client) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() # find dependencies find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(tutorial_interfaces REQUIRED) set(SRC src/client.cpp src/main.cpp ) add_executable(client ${SRC} ) ament_target_dependencies(client rclcpp tutorial_interfaces) # 5. Add header files in the current project note that there are order requirements, Directories (client PRIVATE ${PROJECT_SOURCE_DIR}/include) Find_package (ament_lint_auto REQUIRED) # the following line skips the linter which checks for copyrights # uncomment the line when a copyright and license is not present in all source files # set(ament_cmake_copyright_FOUND TRUE) # the following line skips cpplint (only works in a git repo) # uncomment the line when this package is not in a git repo # set(ament_cmake_cpplint_FOUND TRUE) set(TEST test/main.cpp Test/clienttest.cpp) # generate the test executable file added to gtest. ${PROJECT_NAME}_test is the name of the user-defined test execution file. /demo_test. CPP = test/demo_test. CPP = test/demo_test. CPP = test CPP ament_add_gtest(${PROJECT_NAME}_test ${TEST} SRC /client.cpp) # ament_target_dependencies(${PROJECT_NAME}_test rclcpp tutorial_interfaces) install(TARGETS ${PROJECT_NAME}_test # DESTINATION lib/${PROJECT_NAME}) ament_lint_auto_find_test_dependencies() Install (TARGETS client DESTINATION lib/${PROJECT_NAME}) # Set the build type to Debug mode set(CMAKE_BUILD_TYPE Debug) # Generate coverage files set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") ament_package()Copy the code

Package. The XML file:

<? The XML version = "1.0"? > <? xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> <package format="3"> <name>client</name> <version>0.0.0</version> <description>TODO: Package description</description> <maintainer email="[email protected]">zhi</maintainer> <license>TODO: License declaration</license> <buildtool_depend>ament_cmake</buildtool_depend> <depend>rclcpp</depend> <depend>tutorial_interfaces</depend> <test_depend>ament_lint_auto</test_depend> <test_depend>ament_lint_common</test_depend> <export> <build_type>ament_cmake</build_type> </export> </package>Copy the code

Then go back to the workspace and execute the compile build command:

colcon build --packages-select client
Copy the code

Go to the dev_ws/build/client directory and find the client_test executable that is the generated test file

Start the service package on another terminal:

ros2 run cpp_srvcli server
Copy the code

perform

./client_test 23 3 4
Copy the code

Just run the test file.

Scripts to generate coverage:

#! /usr/bin/bash echo "begin gen coverage file ..." lcov --no-external --capture --initial --directory . --output-file /home/zhi/ros2-gtest-gmock/info/ros2_base.info cd /home/zhi/ros2-gtest-gmock/build/client; ./client_test 45 56 56; CD /home/zh/ros2 -gtest-gmock Current_path =$(PWD) echo "$current_path lcov --no-external --capture --directory. --output-file /home/zhi/ros2-gtest-gmock/info/ros2.info 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 mkdir -p coverage && genhtml /home/zhi/ros2-gtest-gmock/info/ros2_coverage.info --output-directory coverageCopy the code

Program encapsulation rewrite:

If you do not know the return type, just break to see the type:

This article from: www.cnblogs.com/huaibin/p/1…