Creating custom message for ros1_bridge, #include <my_msgs/MyCustom.h> fails
ROS: Kinetic, ROS2: Ardent, OS: Ubuntu 16.04
Hello! This question acts as somewhat of a continuation of my previous question. I'm trying to build a custom message to use with ros1bridge, and in the generated file `<pathtofolder>/ros2ws/build/ros1bridge/generated/mymsgsfactories.hpp, the line
#include <mymsgs/MyCustom.h>is failing while trying to build
ros1_bridge`. The error message is as follows:
In file included from <path_to_folder>/ros2_ws/build/ros1_bridge/generated/get_factory.cpp:25:0:
<path_to_folder>/ros2_ws/build/ros1_bridge/generated/my_msgs_factories.hpp:6:31: fatal error: my_msgs/MyCustom.h: No such file or directory
compilation terminated.
CMakeFiles/ros1_bridge.dir/build.make:156: recipe for target 'CMakeFiles/ros1_bridge.dir/generated/get_factory.cpp.o' failed
As a sanity check, in /opt/ros/kinetic/include
, I created a folder called my_msgs
and placed MyCustom.h
in it, and then it successfully built. Only at this point is my_msgs
seen in the output of ros2 run ros1_bridge dynamic_bridge --print-pairs
. However, when I run dynamic_bridge
after this (using MyCustom
), I get the following output:
Failed to find library 'my_msgs__rosidl_typesupport_introspection_cpp'
failed to create 1to2 bridge for topic '/test_chatter' with ROS 1 type 'my_msgs/MyCustom' and ROS 2 type 'my_msgs/MyCustom': could not create publisher: type support not from this implementation, at <path_to_folder>/ros2_ws/src/ros2/rmw_fastrtps/rmw_fastrtps_cpp/src/rmw_publisher.cpp:75, at <path_to_folder>/ros2_ws/src/ros2/rcl/rcl/src/rcl/publisher.c:151
The contents of <path_to_folder>/ros2_ws/build/ros1_bridge/generated/my_msgs_factories.hpp
and .cpp
are as follows:
//CONTENTS OF my_msgs_factories.hpp
// generated from ros1_bridge/resource/pkg_factories.hpp.em
#include <ros1_bridge/factory.hpp>
// include ROS 1 messages
#include <my_msgs/MyCustom.h>
// include ROS 2 messages
#include <my_msgs/msg/my_custom.hpp>
namespace ros1_bridge
{
std::shared_ptr<FactoryInterface>
get_factory_my_msgs(const std::string & ros1_type_name, const std::string & ros2_type_name);
std::unique_ptr<ServiceFactoryInterface>
get_service_factory_my_msgs(const std::string & ros_id, const std::string & package_name, const std::string & service_name);
// conversion functions for available interfaces
template<>
void
Factory<
my_msgs::MyCustom,
my_msgs::msg::MyCustom
>::convert_1_to_2(
const my_msgs::MyCustom & ros1_msg,
my_msgs::msg::MyCustom & ros2_msg);
template<>
void
Factory<
my_msgs::MyCustom,
my_msgs::msg::MyCustom
>::convert_2_to_1(
const my_msgs::msg::MyCustom & ros2_msg,
my_msgs::MyCustom & ros1_msg);
} // namespace ros1_bridge
And .cpp
:
// CONTENTS OF my_msgs_factories.cpp
// generated from ros1_bridge/resource/pkg_factories.cpp.em
#include "rclcpp/rclcpp.hpp"
#include "my_msgs_factories.hpp"
// include builtin interfaces
#include <ros1_bridge/convert_builtin_interfaces.hpp>
// include ROS 1 services
// include ROS 2 services
namespace ros1_bridge
{
std::shared_ptr<FactoryInterface>
get_factory_my_msgs(const std::string & ros1_type_name, const std::string & ros2_type_name)
{
// mapping from string to specialized template
if (
(ros1_type_name == my_"msgs/MyCustom" ||
ros1_type_name == "") &&
ros2_type_name == "my_msgs/MyCustom")
{
return std::make_shared<
Factory<
my_msgs::MyCustom,
my_msgs::msg::MyCustom
>
>("my_msgs/MyCustom", ros2_type_name);
}
return std::shared_ptr<FactoryInterface>();
}
// conversion functions for available interfaces
template<>
void
Factory<
my_msgs::MyCustom,
my_msgs::msg::MyCustom
>::convert_1_to_2(
const my_msgs::MyCustom & ros1_msg,
my_msgs::msg::MyCustom & ros2_msg)
{
// convert array field
// ensure array size
// dynamic arrays must be resized
ros2_msg.positions.resize(ros1_msg.positions.size());
// convert primitive array elements
std::copy(
ros1_msg.positions.begin(),
ros1_msg.positions.end(),
ros2_msg.positions.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros2_msg.velocities.resize(ros1_msg.velocities.size());
// convert primitive array elements
std::copy(
ros1_msg.velocities.begin(),
ros1_msg.velocities.end(),
ros2_msg.velocities.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros2_msg.currents.resize(ros1_msg.currents.size());
// convert primitive array elements
std::copy(
ros1_msg.currents.begin(),
ros1_msg.currents.end(),
ros2_msg.currents.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros2_msg.temperatures.resize(ros1_msg.temperatures.size());
// convert primitive array elements
std::copy(
ros1_msg.temperatures.begin(),
ros1_msg.temperatures.end(),
ros2_msg.temperatures.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros2_msg.position_error.resize(ros1_msg.position_error.size());
// convert primitive array elements
std::copy(
ros1_msg.position_error.begin(),
ros1_msg.position_error.end(),
ros2_msg.position_error.begin());
}
template<>
void
Factory<
my_msgs::MyCustom,
my_msgs::msg::MyCustom
>::convert_2_to_1(
const my_msgs::msg::MyCustom & ros2_msg,
my_msgs::MyCustom & ros1_msg)
{
// convert array field
// ensure array size
// dynamic arrays must be resized
ros1_msg.positions.resize(ros2_msg.positions.size());
// convert primitive array elements
std::copy(
ros2_msg.positions.begin(),
ros2_msg.positions.end(),
ros1_msg.positions.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros1_msg.velocities.resize(ros2_msg.velocities.size());
// convert primitive array elements
std::copy(
ros2_msg.velocities.begin(),
ros2_msg.velocities.end(),
ros1_msg.velocities.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros1_msg.currents.resize(ros2_msg.currents.size());
// convert primitive array elements
std::copy(
ros2_msg.currents.begin(),
ros2_msg.currents.end(),
ros1_msg.currents.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros1_msg.temperatures.resize(ros2_msg.temperatures.size());
// convert primitive array elements
std::copy(
ros2_msg.temperatures.begin(),
ros2_msg.temperatures.end(),
ros1_msg.temperatures.begin());
// convert array field
// ensure array size
// dynamic arrays must be resized
ros1_msg.position_error.resize(ros2_msg.position_error.size());
// convert primitive array elements
std::copy(
ros2_msg.position_error.begin(),
ros2_msg.position_error.end(),
ros1_msg.position_error.begin());
}
std::unique_ptr<ServiceFactoryInterface>
get_service_factory_my_msgs(const std::string & ros_id, const std::string & package_name, const std::string & service_name)
{
(void)ros_id;
(void)package_name;
(void)service_name;
return nullptr;
}
} // namespace ros1_bridge
Furthermore, the contents of <path_to_folder>/ros1_bridge_overlay/catkin_ws_overlay/src/my_msgs/CMakeLists.txt
is:
cmake_minimum_required(VERSION 2.8)
project(my_msgs)
find_package(catkin REQUIRED COMPONENTS
message_generation
roscpp
)
add_message_files(
FILES
MyCustom.msg
)
generate_messages()
catkin_package(
INCLUDE_DIRS include
CATKIN_DEPENDS message_runtime roscpp
)
include_directories(${catkin_INCLUDE_DIRS})
add_executable(pub src/pub.cpp)
target_link_libraries(pub ${catkin_LIBRARIES})
install(
DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
I think my problem is that I'm not installing ROS1's version of my_msgs
correctly, hence my inclusion of the CMakeLists file. Any suggestions would be much appreciated!
EDIT #1: my build process and starting up the nodes is very similar to Example #1 in ros1_bridge's README, the only differences being that I source the overlay workspaces when necessary.
I delete the build folder in ros1_bridge, and rebuild with the following process:
$ source /opt/ros/kinetic/setup.bash
$ source <path_to_folder>/ros2_ws/install/local_setup.bash //My core ros2 workspace
$ source <path_to_folder>/ros1_bridge_overlay/catkin_ws_overlay/devel/setup.bash //ROS1 ws
$ source <path_to_folder>/ros1_bridge_overlay/ros2_ws_overlay/install/local_setup.bash //ROS2 ws
$ src/ament/ament_tools/scripts/ament.py build --build-tests --symlink-install --only ros1_bridge --force-cmake-configure
EDIT #2: the above command is where the original build fails and throws the initial error.
Then, in separate terminal windows:
Starting roscore:
$ source /opt/ros/kinetic/setup.bash
$ roscore
Starting the bridge:
$ source /opt/ros/kinetic/setup.bash
$ source <path_to_folder>/ros2_ws/install/local_setup.bash //Contains ros1_bridge
$ source <path_to_folder>/ros1_bridge_overlay/catkin_ws_overlay/devel/setup.bash
$ source <path_to_folder>/ros1_bridge_overlay/ros2_ws_overlay/install/local_setup.bash
$ export ROS_MASTER_URI=http://localhost:11311
$ ros2 run ros1_bridge dynamic_bridge
Starting the ROS1 publisher:
$ source /opt/ros/kinetic/setup.bash
$ source <path_to_folder>/ros1_bridge_overlay/catkin_ws_overlay/devel/setup.bash
$ rosrun my_msgs pub
Starting the ROS2 subscriber:
$ source /opt/ros/kinetic/setup.bash
$ source <path_to_folder>/ros2_ws/install/local_setup.bash
$ source <path_to_folder>/ros1_bridge_overlay/ros2_ws_overlay/install/local_setup.bash
$ ros2 run my_msgs sub
Asked by Rob V on 2018-07-27 15:52:15 UTC
Comments
Did you source your ROS 1 workspace after building it? Please try to include the exact steps you did with which you can reproduce the problem.
Asked by Dirk Thomas on 2018-07-27 16:20:20 UTC
See my above edit... Thanks for helping out again!!
Asked by Rob V on 2018-07-27 17:00:13 UTC
Your original post mentioned that the include failed. So you shouldn't be able to build successfully. You might want to revert your manual changes to
/opt/ros/kinetic
to reproduce the original problem.Asked by Dirk Thomas on 2018-07-27 17:03:58 UTC
You should only need to source a single ws per ROS version. In ROS 1 your overlay workspace will automatically source the underlay which was used to build that ws. In ROS 2 that works the same when you source the
setup.*
instead of thelocal_setup.*
.Asked by Dirk Thomas on 2018-07-27 17:05:15 UTC
Good point... However, when I revert it back, that's the same procedure I follow too. See the above minor edit at EDIT #2. Also, didn't know about that
setup
functionality. Good to know.Asked by Rob V on 2018-07-27 17:08:45 UTC