Ros2 learning notes 16 -- detail ros2 interface

Summary: This article mainly introduces the ros2 interface in more depth

Environment: Ubuntu 20 04,ros2-foxy,vscode

Finally, if there are no problems encountered in the actual operation, it means that the chapter can be reproduced normally by myself

2.2.8 expand ros2 interface (original text: https://docs.ros.org/en/foxy/Tutorials/Single-Package-Define-And-Use-Interface.html )

>>Tutorial > > expand ros2 interface

You are reading the documentation of the older version of ros2 (Foxy), but it still supports. For information on the latest version, please see the Galactic version link( https://docs.ros.org/en/galactic/Tutorials.html )

Detailed ros2 interface

Objective: learn more ways to use custom ros2 interfaces

Course level: Elementary

Duration: 15min

catalogue

1. Background
2. Preparatory knowledge
3. Steps
3.1 create a package
3.2 create an msg file
3.3 use the same interface of the same package
3.4 testing
3.5 (additional) use of existing interface definitions
4. Summary
5. Next step
6. Relevant contents

1. Background

In the previous lesson, you learned how to create customized msg and srv interfaces

Although it is best to declare an interface in a dedicated interface package, it is sometimes (more) convenient to declare, create and use interfaces in the same package

As mentioned earlier, interfaces can only be defined in cmake packages. However, (if you use ament_cmake_python) Python libraries and nodes may be in cmake packages, so it is feasible to define Python nodes and interfaces in a package. For simplicity, cmake packages and c + + nodes are used here

This course focuses on msg type interfaces, but these steps apply to all types of interfaces

2. Preparatory knowledge

Suppose you reviewed the basics of creating custom msg and srv files before starting this course

You should have installed ros2, have a workspace, and know how to create packages

As the old rule, when you open a new terminal, don't forget the ros2 environment variable

3. Steps

3.1 create a package

Create an src directory line in your workspace called more_interfaces package, which also creates a folder for msg files:

ros2 pkg create --build-type ament_cmake more_interfaces
mkdir more_interfaces/msg

3.2 create an msg file

In more_ On the basis of interfaces / MSG, create a new file addressbook msg.

Copy the following code to create a message (type), which represents a person's information:

bool FEMALE=true
bool MALE=false

string first_name
string last_name
bool gender
uint8 age
string address

The information consists of five parts:

Last name: string type
Name: string type
Gender: Boolean type, either male or female
Age: unit8 type
Address: string type

Note that default parameters can be set in some places. See here( https://docs.ros.org/en/foxy/Concepts/About-ROS-Interfaces.html#interfaceconcept ), you can find many ways to customize interfaces

Next, we need to confirm that the msg file can use the source code of c++,python or other languages

3.2.1 create an msg file

Open the file package XML, add the following lines:

<buildtool_depend>rosidl_default_generators</buildtool_depend>

<exec_depend>rosidl_default_runtime</exec_depend>

<member_of_group>rosidl_interface_packages</member_of_group>

Note that when compiling, we need rosidl_default_generators; At runtime, we only need rosidl_default_runtime.

Open cmakelists Txt, add the following lines:

Find the package and generate the msg/srv file into the message type:

find_package(rosidl_default_generators REQUIRED)

Declare the list of message types you want to generate:

set(msg_files
  "msg/AddressBook.msg"
)

Add manually msg file, we make sure cmake can be found when you add others After the msg file, cmake must reset the system configuration

Generate message:

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
)

Also ensure that you export the dependency of the information Runtime:

ament_export_dependencies(rosidl_default_runtime)

Now, you can use the custom msg file to generate a source file. When the above four steps are completed, we will skip the compilation step directly

3.2.2 (special) setting multiple interfaces

be careful:

You can use set to concisely list interfaces:

set(msg_files
  "msg/Message1.msg"
  "msg/Message2.msg"
  # etc
  )

set(srv_files
  "srv/Service1.srv"
  "srv/Service2.srv"
   # etc
  )

Generate all enumerated at once, like this:

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  ${srv_files}
)

3.3 use the same interface of the same package

Now let's start coding with this message type:

In more_ Create the file publish in the interfaces / SRC directory_ address_ book. CPP, and copy the following code into it:

#include <chrono>
#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "more_interfaces/msg/address_book.hpp"

using namespace std::chrono_literals;

class AddressBookPublisher : public rclcpp::Node
{
public:
  AddressBookPublisher()
  : Node("address_book_publisher")
  {
    address_book_publisher_ =
      this->create_publisher<more_interfaces::msg::AddressBook>("address_book", 10);

    auto publish_msg = [this]() -> void {
        auto message = more_interfaces::msg::AddressBook();

        message.first_name = "John";
        message.last_name = "Doe";
        message.age = 30;
        message.gender = message.MALE;
        message.address = "unknown";

        std::cout << "Publishing Contact\nFirst:" << message.first_name <<
          "  Last:" << message.last_name << std::endl;

        this->address_book_publisher_->publish(message);
      };
    timer_ = this->create_wall_timer(1s, publish_msg);
  }

private:
  rclcpp::Publisher<more_interfaces::msg::AddressBook>::SharedPtr address_book_publisher_;
  rclcpp::TimerBase::SharedPtr timer_;
};


int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<AddressBookPublisher>());
  rclcpp::shutdown();

  return 0;
}

3.3.1 code analysis

#include "more_interfaces/msg/address_book.hpp"

Contains the newly created addressbook MSG header file

using namespace std::chrono_literals;

class AddressBookPublisher : public rclcpp::Node
{
public:
  AddressBookPublisher()
  : Node("address_book_publisher")
  {
    address_book_publisher_ =
      this->create_publisher<more_interfaces::msg::AddressBook>("address_book");

Create a node and AddressBook Publisher:

auto publish_msg = [this]() -> void {

Create a callback to publish messages periodically:

auto message = more_interfaces::msg::AddressBook();

Create the AddressBook message we will publish later:

message.first_name = "John";
message.last_name = "Doe";
message.age = 30;
message.gender = message.MALE;
message.address = "unknown";

Output each item of AddressBook:

std::cout << "Publishing Contact\nFirst:" << message.first_name <<
  "  Last:" << message.last_name << std::endl;

this->address_book_publisher_->publish(message);

Finally, regularly publish news:

timer_ = this->create_wall_timer(1s, publish_msg);

Create a 1-second timer to call publish once per second_ MSG function

3.3.2 compiler publisher

At cmakelists Txt file, we need to create a new target for this node:

find_package(rclcpp REQUIRED)

add_executable(publish_address_book
  src/publish_address_book.cpp
)

ament_target_dependencies(publish_address_book
  "rclcpp"
)

install(TARGETS publish_address_book
 DESTINATION lib/${PROJECT_NAME})

3.3.3 connect the specified interface

In order to use the generated message type in the same package, we need to use the following CMake Code:

rosidl_target_interfaces(publish_address_book
  ${PROJECT_NAME} "rosidl_typesupport_cpp")

This will find the address book MSG prepared by the relevant c + + code, let you target targeted connection it

You may find that this step is not necessary when the interface used is from another package. When we use the interface to the same package (operation package and interface package belong to the same), this CMake code is necessary

3.4 testing

Return to the root directory of the workspace and compile the package:

linux:

cd ~/dev_ws
colcon build --packages-up-to more_interfaces

Then source the workspace (environment variable) and run the publisher:

linux:

. install/local_setup.bash
ros2 run more_interfaces publish_address_book

We won't create listeners this time, but you can try to write an exercise (refer to the course of writing simple publishers and listeners (c + +)

3.5 (special) use of existing interface definitions

be careful:

You can use an existing interface definition for a new interface definition. For example, here, a message type is contact MSG, which belongs to rosidl in the ros2 package_ tutorials_ Msgs, assuming that its definition is equivalent to the previously customized addressbook MSG interface

In this case, you have defined addressbook MSG (the interface and your node are in the same package) as the type Contact (the package of the interface and operation node are different), like this:

rosidl_tutorials_msgs/Contact[] address_book

In order to generate this message (type), you should be in contact Package. In MSG package XML file declaration dependency, rosidl_tutorials_msgs:

<build_depend>rosidl_tutorials_msgs</build_depend>

<exec_depend>rosidl_tutorials_msgs</exec_depend>

At cmakelists Txt file add:

find_package(rosidl_tutorials_msgs REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  DEPENDENCIES rosidl_tutorials_msgs
)

In order to add contacts to your address_ In the book publisher node, you want to add a contact MSG header file

#include "rosidl_tutorials_msgs/msg/contact.hpp"

You change something in the callback section, like this:

auto publish_msg = [this]() -> void {
   auto msg = std::make_shared<more_interfaces::msg::AddressBook>();
   {
     rosidl_tutorials_msgs::msg::Contact contact;
     contact.first_name = "John";
     contact.last_name = "Doe";
     contact.age = 30;
     contact.gender = contact.MALE;
     contact.address = "unknown";
     msg->address_book.push_back(contact);
   }
   {
     rosidl_tutorials_msgs::msg::Contact contact;
     contact.first_name = "Jane";
     contact.last_name = "Doe";
     contact.age = 20;
     contact.gender = contact.FEMALE;
     contact.address = "unknown";
     msg->address_book.push_back(contact);
   }

   std::cout << "Publishing address book:" << std::endl;
   for (auto contact : msg->address_book) {
     std::cout << "First:" << contact.first_name << "  Last:" << contact.last_name <<
       std::endl;
   }

   address_book_publisher_->publish(*msg);
 };

After compiling and running the changes, it will show the expected message type msg and the message msg array defined above

4. Summary

In this course, you tried different ways to define interfaces, and then (practiced) how to build an interface and use it in the same package

You should also learn how to use another interface as a type, package xml, CMakeLists. Txt, and #include declaration (how to write) to use (the interface function) is also necessary

5. Next step

Next, you will create a simple ros2 package and learn how to set the customized parameters in the launch file. Of course, you can choose c + + or python to write it (package source file)

6. Relevant contents

Here are several design documents( https://design.ros2.org/#interfaces )About ros2 interface and IDL (interface definition language)

other

I think the key points are:

The same package, the implementation of interface definition and call, and the file configuration mode in the package;

When other existing interfaces are used as new interfaces, the configuration mode of files in the package

****************
Personal problems: the custom msg cannot generate header files. The reason is unknown; Because the previous compilation can not pass, there is no practical operation to practice using the existing interface definition file later

The error reason is cmake error, that is, cmakelists There is a problem with the following statement in TXT file:

rosidl_target_interfaces(publish_address_book
  ${PROJECT_NAME} "rosidl_typesupport_cpp")

Compilation error reporting window prompt:

CMake Error at /opt/ros/foxy/share/rosidl_cmake/cmake/rosidl_target_interfaces.cmake:40 (message):
  rosidl_target_interfaces() the second argument 'more_interfaces' must be a
  valid target name
Call Stack (most recent call first):
  CMakeLists.txt:31 (rosidl_target_interfaces)

This problem hasn't been solved yet. Please leave a message if you know. Thank you
*****************
This course was held for more than ten days after the graduation certificate. My roommate asked, why are you still fooling around here because online translation is so powerful now? I said, my goal is to take a good look, understand and toss myself. At present, I think of the best way to get the best effect, even if the translation is a little awkward, ha ha ha

#####################
No silicon steps, no even thousands of miles
A good memory is better than a bad pen
If you feel a little harvest, please praise the collection

Keywords: ROS2

Added by dylan001 on Fri, 21 Jan 2022 20:18:44 +0200