0
$\begingroup$

I have a package with two nodes, that are communicating internally. For that reason I would like to create a custom msg to transfer data between them. I've followed this tutorial, which basically sets the following points:

  1. add msg/Custom.msg with the message content
  2. add the following to 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>

3.Add the following to CMakelists.txt:

find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}  "msg/Custom.msg")
  1. in your source: devenv/msg/custom.hpp

(please note that I don't use an interface package, as this is intra-package communication communication)

I can see that the file is generetade in : build/devenv/rosidl_generator_cpp/devenv/msg/custom.hpp

No matter what I've tried, I can't include thie hpp file, what am I doing wrong?

$\endgroup$

1 Answer 1

2
$\begingroup$

The short version is, you need to tell CMake where to find the targets generated for the interfaces and link your own executable/library targets to them. You can do this using the rosidl_target_interfaces macro on Galactic and below, or the rosidl_get_typesupport_target macro on Humble and newer.


Here's the long explanation.

In general, an interface package is recommended because it makes it easier to share the interface definitions with other packages and projects. However your situation of wanting to use the interface only within one single package is a completely valid use case, and it is supported. It's just not as easy to do.

The problem you are encountering is occurring because when you add an interface, the rosidl_generate_interfaces CMake macro is creating a bunch of targets for generated header and source files and related compiled libraries behind the scenes. These targets and header files are installed automatically, but they don't get added to the default include or link paths for other targets in your CMakeLists.txt file. (In other words, all the rosidl machinery is oriented towards having separate interface packages.)

In order to solve your problem, you need to find the target that is generated by the rosidl machinery and link your node(s) to it. That will bring in the include and link paths, allowing your own code to find the generated header files from the same package.

In ROS 2 Galactic and lower, this is done using the rosidl_target_interfaces macro.

So if I add some interfaces to be generated using the PROJECT_NAME as the name of the interfaces target:

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/MyInterface.msg"
)

And assuming I have a node executable named my_node (the approach is identical for a library if you are building component nodes), I can fix the include and linking problem with this line:

rosidl_target_interfaces(my_node ${PROJECT_NAME} "rosidl_typesupport_cpp")

If you are using ROS 2 Humble or newer (or Rolling), then there is a better approach available now. Replace the above line with these two lines:

rosidl_get_typesupport_target(cpp_typesupport_target ${PROJECT_NAME} "rosidl_typesupport_cpp")
target_link_libraries(my_node "${cpp_typesupport_target}") 

This new approach is preferred because it gets the target, which potentially supports modern CMake target-based information sharing.

For an example of this in practice, see the common_interfaces package. This package provides many interfaces, but it also tests them. In order for the tests to compile they have to be able to find the interfaces provided by the same package.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.