ros1_bridge: ros1_bridge does not bridge service if service field name changes, even if mapped in mapping_rules.yaml

Bug report

I have found that if a service field name changes between ROS1 and ROS2, even if the change is mapped in a mapping_rules.yaml, does not bridge the service.

Required Info:

  • Operating System:
    • Ubuntu 20.04.
  • Installation type:
    • Source
  • Version or commit hash:
    • Tag 0.9.4
  • DDS implementation:
    • Default (Fast RTPS)
  • Client library (if applicable):
    • N/A

Steps to reproduce issue

I created a stripped down project to demonstrate the issue:

.
├── ros1_ws
│   └── src
│       └── example_interfaces
│           ├── CMakeLists.txt
│           ├── package.xml
│           └── srv
│               ├── CustomServiceFails.srv
│               └── CustomServiceSucceeds1.srv
└── ros2_ws
    └── src
        └── example_interfaces
            ├── CMakeLists.txt
            ├── mapping_rules.yaml
            ├── package.xml
            └── srv
                ├── CustomServiceFails.srv
                └── CustomServiceSucceeds2.srv

ROS1 CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)

project(example_interfaces)

set(MSG_DEPS std_msgs)

set(BUILD_DEPS ${MSG_DEPS} message_generation)

set(RUNTIME_DEPS ${MSG_DEPS} message_runtime)

find_package(catkin REQUIRED COMPONENTS ${BUILD_DEPS})

add_service_files(DIRECTORY srv FILES
    CustomServiceFails.srv
    CustomServiceSucceeds1.srv
)

generate_messages(DEPENDENCIES ${MSG_DEPS})

catkin_package(CATKIN_DEPENDS ${RUNTIME_DEPS})

ROS1 package.xml

<?xml version="1.0" ?>
<package format="2">
  <name>example_interfaces</name>
  <version>0.0.1</version>
  <description>
    This pacakge contains a single service to demonstrate a bug in the ros1_bridge
  </description>
  <maintainer email="joshua.raanan@gmail.com">Joshua Ra'anan</maintainer>

  <license>BSD</license>
  <buildtool_depend>catkin</buildtool_depend>

  <depend>std_msgs</depend>

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

  <export>
  </export>
</package>

ROS1 CustomServiceFails.srv

float64 same_field_name
---
float64 differentFieldName

ROS1 CustomServiceSucceeds1.srv

float64 fine_name
---
float64 also_fine_name

ROS2 CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(example_interfaces)

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

set(MSG_DEPS
  std_msgs
)

set(BUILD_DEPS
  ament_cmake
  rosidl_default_generators
  ${MSG_DEPS}
)

foreach(DEP ${BUILD_DEPS})
  find_package(${DEP} REQUIRED)
endforeach()

find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
    srv/CustomServiceFails.srv
    srv/CustomServiceSucceeds2.srv
DEPENDENCIES ${MSG_DEPS}
)

install(
  FILES mapping_rules.yaml
  DESTINATION share/${PROJECT_NAME})

ament_export_dependencies(rosidl_default_runtime)

ament_package()

ROS2 package.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>example_interfaces</name>
  <version>0.0.1</version>
  <description>
    This pacakge contains a single service to demonstrate a bug in the ros1_bridge
  </description>
  <maintainer email="joshua.raanan@gmail.com">Joshua Ra'anan</maintainer>

  <license>BSD</license>
  
  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>std_msgs</depend>

  <buildtool_depend>rosidl_default_generators</buildtool_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>

  <member_of_group>rosidl_interface_packages</member_of_group>

  <export>
    <build_type>ament_cmake</build_type>
    <ros1_bridge mapping_rules="mapping_rules.yaml"/>
  </export>

</package>

ROS2 mapping_rules.yaml

-
    ros1_package_name: "example_interfaces"
    ros1_service_name: "CustomServiceSucceeds1"
    ros2_package_name: "example_interfaces"
    ros2_service_name: "CustomServiceSucceeds2"
-
    ros1_package_name: "example_interfaces"
    ros1_service_name: "CustomServiceFails"
    ros2_package_name: "example_interfaces"
    ros2_service_name: "CustomServiceFails"
    request_fields_1_to_2:
        same_field_name: "same_field_name"
    response_fields_1_to_2:
        differentFieldName: "different_field_name"

ROS2 CustomServiceFails.srv

float64 same_field_name
---
float64 different_field_name

ROS2 CustomServiceSucceeds2.srv

float64 fine_name
---
float64 also_fine_name

The build instructions are the default instructions:

cd . <ros1-workspace-path>/
. /opt/ros/noetic/setup.bash
catkin build
cd . <ros2-workspace-path>/
. /opt/ros/noetic/setup.bash
colcon build
. <ros1-workspace-path>/example_interfaces/devel/setup.bash
. <ros2-workspace-path>/example_interfaces/install/local_setup.bash
colcon build --packages-select ros1_bridge --cmake-force-configure

Checking the --print-pairs shows that the CustomServiceFails.srv is not mapped.

Expected behavior

The expected behavior is that both example_interfaces/CustomServiceSucceeds and example_interfaces/CustomServiceFails are bridged.

Actual behavior

What actually happens is that only example_interfaces/CustomServiceSucceeds is bridged and example_interfaces/CustomServiceFails is not bridged.

Supported ROS 2 <=> ROS 1 service type conversion pairs:
  - 'diagnostic_msgs/srv/AddDiagnostics' (ROS 2) <=> 'diagnostic_msgs/AddDiagnostics' (ROS 1)
  - 'diagnostic_msgs/srv/SelfTest' (ROS 2) <=> 'diagnostic_msgs/SelfTest' (ROS 1)
  - 'example_interfaces/srv/CustomServiceSucceeds2' (ROS 2) <=> 'example_interfaces/CustomServiceSucceeds1' (ROS 1)
  - 'gazebo_msgs/srv/BodyRequest' (ROS 2) <=> 'gazebo_msgs/BodyRequest' (ROS 1)

Additional information

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 1
  • Comments: 17 (10 by maintainers)

Commits related to this issue

Most upvoted comments

First things first: apologies for disappointing, but I am not bringing a solution to your problem.

I have stumbled on the same issue. I have two service definitions that use the same type but due to the ROS2 naming convention the names themselves deffer. I set up the mapping_rules accordingly but there was no result. I did some additional digging and I think that I found the issue.

Line number 612 in init.py states:

if (ros1_type, ros2_type) not in message_string_pairs:
     match = False
     break

In my case ros1_type & ros2_type are both uint8 but because they are compared to a member of message_string_pairs that is ('std_msgs/UInt8', 'std_msgs/UInt8') this check fails.

Here is the snippet from the .srv files. ROS1 Service

...
uint8 outputNr 
...

ROS2 Service

...
uint8 output_nr 
...

And the snippet from the mapping_rules:

...
request_fields_1_to_2:
    outputNr: "output_nr"
...

I have not yet investigated the solution but I think the issue resides there. Developers, please let me know if I am barking at the wrong tree or if I there is some sense here.

https://github.com/ros2/ros1_bridge/pull/256/commits/07467973c329e430cd2c101729962d8ed075885f builds fine for me. These are the mappings I get:

emplate <>
void ServiceFactory<
  example_interfaces::CustomServiceFails,
  example_interfaces::srv::CustomServiceFails
>::translate_1_to_2(
  const example_interfaces::CustomServiceFails::Request& req1,
  example_interfaces::srv::CustomServiceFails::Request& req2
) {
  auto & same_field_name1 = req1.same_field_name;
  auto & same_field_name2 = req2.same_field_name;
  same_field_name2 = same_field_name1;
}

template <>
void ServiceFactory<
  example_interfaces::CustomServiceFails,
  example_interfaces::srv::CustomServiceFails
>::translate_1_to_2(
  const example_interfaces::CustomServiceFails::Response& req1,
  example_interfaces::srv::CustomServiceFails::Response& req2
) {
  auto & differentFieldName1 = req1.differentFieldName;
  auto & different_field_name2 = req2.different_field_name;
  different_field_name2 = differentFieldName1;
}

template <>
void ServiceFactory<
  example_interfaces::CustomServiceFails,
  example_interfaces::srv::CustomServiceFails
>::translate_2_to_1(
  const example_interfaces::srv::CustomServiceFails::Request& req2,
  example_interfaces::CustomServiceFails::Request& req1
) {
  auto & same_field_name1 = req1.same_field_name;
  auto & same_field_name2 = req2.same_field_name;
  same_field_name1 = same_field_name2;
}

template <>
void ServiceFactory<
  example_interfaces::CustomServiceFails,
  example_interfaces::srv::CustomServiceFails
>::translate_2_to_1(
  const example_interfaces::srv::CustomServiceFails::Response& req2,
  example_interfaces::CustomServiceFails::Response& req1
) {
  auto & differentFieldName1 = req1.differentFieldName;
  auto & different_field_name2 = req2.different_field_name;
  differentFieldName1 = different_field_name2;
}

I will extend this for services as well and then you could check again.

@tgaspar

I’d like to contribute to this issue. If you don’t mind, could you help review https://github.com/ros2/ros1_bridge/pull/293?