ros2/ros1_bridge

[Humble] No conversion from `rcl_interfaces/msg/Log` and `rosgraph_msgs/Log`

Timple opened this issue ยท 21 comments

Bug report

Required Info:

  • Operating System:
    • Docker (ubuntu:jammy)
  • Installation type:
    • ROS1 from ubuntu binaries
    • ROS2 from source (because of catkin conflict)
    • ros_bridge from source
  • Version or commit hash:
    • master
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):

Steps to reproduce issue

git clone https://github.com/contradict/ros-humble-ros1-bridge.git
cd ros-humble-ros1-bridge
docker build . -t bridge

Then run with this docker-compose file:

version: "2.1"
services:
  roscore:
    image: "ros:noetic"
    network_mode: host
    command: roscore
  ros1-bridge:
    image: bridge
    network_mode: host
    command: ros2 run ros1_bridge dynamic_bridge

Expected behavior

Bridging /rosout

Actual behavior

Not bridging /rosout

Additional information

Seems like the mapping is not found: https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/mapping_rules.yaml

Relevant other issues:

#159 Was fixed, is broken again for humble
contradict/ros-humble-ros1-bridge#2 (Not the fault of the dockerfile I think)

PS. Also seems to be the case for rolling.

Not a fix, but a workaround to enable the use of ROS1 bridge with the above Dockerfile (without logging):

Instead of roscore run rosmaster --core

But that would mean I would need to configure all nodes to run without /rosout right?

Hi! Were you able to resolve the issue? I am also experiencing the same error.

I did something similar here, but with the addition of rosbridge_suite: https://github.com/brow1633/ros_docker/blob/main/ros-humble-bridge

I'm not sure about configuring other nodes. I haven't run into issues, but haven't run this extensively to be honest.

@brow1633 because you are using rosmaster --core instead of roscore.
Therefore you simply skip logging and there is no issue with converting the logging message.

So this #393 (comment) led me to investigate the history.

The last working commit for Log messages was 81f8b08. Since 2381bf4 it's broken (PR #382).

@LoyVanBeek did you ever run in to problems with Log messages?

Hey Tim

Nope, have never tried bridging those until now.
We only use the parameter_bridge. When I configure it to bridge /rosout and type rcl_interfaces/msg/Log with this config:

topics:
  - topic: /rosout
    type: rcl_interfaces/msg/Log
    queue_size: 1

I get:

failed to create bidirectional bridge for topic '/rosout' with ROS 2 type 'rcl_interfaces/msg/Log': No template specialization for the pair

We're still on Foxy + Noetic btw.

Even with the mapping rules in https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/mapping_rules.yaml, the 'enum' for error levels also doesn't yet line up. And the ROS1 field topics[] is also missing from the ROS 2 variant.
But I'd expect that to be fine:
2381bf4#diff-addbc08357f431e24b7c461dce9513f7aa52338c08319c8929b17e213a9e4037R808-R822

    ros1_field_missing_in_ros2 = any(ros1_fields_not_mapped)

    if ros1_field_missing_in_ros2:
        # if some fields exist in ROS 1 but not in ROS 2
        # check that no fields exist in ROS 2 but not in ROS 1
        # since then it might be the case that those have been renamed and should be mapped
        for ros2_member in ros2_spec.structure.members:
            for ros1_field in ros1_spec.parsed_fields():
                if ros1_field.name.lower() == ros2_member.name:
                    break
            else:
                # if fields from both sides are not mappable the whole message is not mappable
                return None
return mapping

So I'm not sure what the problem is. I have a branch on my fork https://github.com/LoyVanBeek/ros1_bridge/tree/debug/mapping_uuids that adds a whole bunch of logging to pinpoint this. All I have to offer at the moment.

Yes, i found the same issue for rolling ros2 version. i installed the ros noetic version in my ubuntu22 docker container built from source. and when I print out the pairs, there is no output like this:
" - 'rcl_interfaces/msg/Log' (ROS 2) <=> 'rosgraph_msgs/Log' (ROS 1)"

I have tried many methods to solve this problem, but it does not work. i would appreciate that If anybody could provide a solution to it.

Yes, i found the same issue for rolling ros2 version. i installed the ros noetic version in my ubuntu22 docker container built from source. and when I print out the pairs, there is no output like this: " - 'rcl_interfaces/msg/Log' (ROS 2) <=> 'rosgraph_msgs/Log' (ROS 1)"

I have tried many methods to solve this problem, but it does not work. i would appreciate that If anybody could provide a solution to it.

Hi guys, I have solved this problem with this commit b9f1739.
My work env is (ubuntu 22 jammy + build from source ros noetic + ros2 rolling) docker container.

Timple commented

You are pointing to a commit that modified a typo in a readme. I guess you meant another commit?

This commit 81f8b08 is still stuck on the same issue that /rosout topics cannot be mapped.
Nope, this commit solved my problem. b9f1739

is there a solution to this problem?
failed to create 2to1 bridge for topic '/rosout' with ROS 2 type 'rcl_interfaces/msg/Log' and ROS 1 type 'rosgraph_msgs/Log': No template specialization for the pair

do we just checkout the code at this point of commit b9f1739?

Timple commented

We do.
But it's a shame we miss all the new features and improvements that are being implemented.

But that's how it goes: workaround is in place, so the issue plunges down the backlog ๐Ÿ™

@Timple,

Thanks for the follow up. I modified https://github.com/contradict/ros-humble-ros1-bridge/blob/main/Dockerfile to checkout the commit.
Screenshot from 2023-11-14 17-05-29

Afterwards, I tried running the examples.
I have the following docker containers running with -net=host option.

ros-humble-ros1-bridge running ros1-bridge
osrf/ros:noetic-desktop-full running roscore
osrf/ros:noetic-desktop-full for running ros1 talker
osrf/ros:humble-desktop-full for running ros2 listener

i can see that the bridge is connected
Screenshot from 2023-11-14 17-13-44

but my listener is not outputting anything.
Screenshot from 2023-11-14 17-14-39

is there another bug i am unaware of?

update

I run the commnad
ros2 topic info /chatter --verbose
Type: std_msgs/msg/String

Publisher count: 1

Node name: NODE_NAME_UNKNOWN
Node namespace: NODE_NAMESPACE_UNKNOWN
Topic type: std_msgs/msg/String
Endpoint type: PUBLISHER
GID: 01.0f.0c.f2.55.00.80.68.01.00.00.00.00.00.12.03.00.00.00.00.00.00.00.00
QoS profile:
Reliability: RELIABLE
History (Depth): UNKNOWN
Durability: VOLATILE
Lifespan: Infinite
Deadline: Infinite
Liveliness: AUTOMATIC
Liveliness lease duration: Infinite

Subscription count: 1

Node name: NODE_NAME_UNKNOWN
Node namespace: NODE_NAMESPACE_UNKNOWN
Topic type: std_msgs/msg/String
Endpoint type: SUBSCRIPTION
GID: 01.0f.0c.f2.55.00.80.68.01.00.00.00.00.00.13.04.00.00.00.00.00.00.00.00
QoS profile:
Reliability: BEST_EFFORT
History (Depth): UNKNOWN
Durability: VOLATILE
Lifespan: Infinite
Deadline: Infinite
Liveliness: AUTOMATIC
Liveliness lease duration: Infinite

and apparently the Node name for the ros1_bridge package in my ros2 humble docker is not defined. NODE_NAME_UNKNOWN
i am expecting the node to be ros1_bridge as i can see it in my ros1 noetic docker with rosnode list.

issue resolved

problem was my docker network configuration and host firewall settings, the ros1_bridge works fine.
recommend to disable firewall with
sudo ufw disable

Timple commented

Not to my knowledge.

But if you go bug-hunting: might as well try the master ๐Ÿ˜‰

Hi. This thread helped me a lot in getting the ros1-bridge to work on my ROS2 Humble + ROS Noetic setup. I've created a Docker image that can build the ros-humble-ros1-bridge package in 10 minutes -- no need to compile ROS2 Humble from the source. You can find my setup here:
https://github.com/TommyChangUMD/ros-humble-ros1-bridge-builder/

KKSTB commented

Hi @TommyChangUMD

Nice work. I actually made it to work on ROS2 Iron + ROS Noetic. Also the bridge works by copying the build output into my ROS2 install folder which is very neat and clean.

I'm running a horrible amalgamation of master + action support + some cherry picked fixes. I had to create custom convert_2_to_1 template specializations to convert the severity levels between ros1/ros2. The dynamic bridge needed an extra check to set the QoS for /rosout as well. The other nodes might need that too, but I haven't looked at them.

I'm not sure if this repo is still alive, or will accept changes for humble.

I think the issue is with the is_package_mapping() method in this code snippet from __init__.py:

def determine_package_pairs(ros1_msgs, ros2_msgs, mapping_rules):
    pairs = []
    # determine package names considered equal between ROS 1 and ROS 2
    ros1_suffix = '_msgs'
    ros2_suffixes = ['_msgs', '_interfaces']
    ros1_package_names = {m.package_name for m in ros1_msgs}
    ros2_package_names = {m.package_name for m in ros2_msgs}
    for ros1_package_name in ros1_package_names:
        if not ros1_package_name.endswith(ros1_suffix):
            continue
        ros1_package_basename = ros1_package_name[:-len(ros1_suffix)]
        for ros2_package_name in ros2_package_names:
            for ros2_suffix in ros2_suffixes:
                if ros2_package_name.endswith(ros2_suffix):
                    break
            else:
                continue
            ros2_package_basename = ros2_package_name[:-len(ros2_suffix)]
            if ros1_package_basename != ros2_package_basename:
                continue
            pairs.append((ros1_package_name, ros2_package_name))
    # add manual package mapping rules
    for rule in mapping_rules:
        if not rule.is_package_mapping():
            continue
        if rule.ros1_package_name not in ros1_package_names:
            continue
        if rule.ros2_package_name not in ros2_package_names:
            continue
        pair = (rule.ros1_package_name, rule.ros2_package_name)
        if pair not in pairs:
            pairs.append(pair)
    return pairs

In the last loop, the code is maybe trying to add mapping rules that don't share the same package names for ROS 1 and ROS 2, like rosgraph_msgs and rcl_interfaces. However, since rule.is_package_mapping() returns false for these cases, it skips adding that pair to pairs, which is later used for mapping messages.

The is_package_mapping(), which comes from the MappingRule class (the parent of MessageMappingRule), checks this condition:

    len(data) == (2 + int('enable_foreign_mappings' in data))

and the data looks like this:

{
	'ros1_package_name': 'rosgraph_msgs',
	'ros1_message_name': 'Log',
	'ros2_package_name': 'rcl_interfaces',
	'ros2_message_name': 'Log',
	'fields_1_to_2': {'header.stamp': 'stamp', 'level': 'level', 'name': 'name', 'msg': 'msg', 'file': 'file', 'function': 'function', 'line': 'line'}
}

In this case, len(data) equals 5 and int('enable_foreign_mappings' in data) is 0, so the condition if not rule.is_package_mapping() evaluates to true, which leads the code to exit the loop without adding the pair to pairs.

I'm not quite sure about the purpose of the check len(data) == (2 + int('enable_foreign_mappings' in data)), so I'm uncertain about how to fix this code.

This might be related to #367, which introduced the enable_foreign_mappings flag around 2 years ago. The mapping file for the rcl_interfaces package was added about 5 years ago, so it doesn't set that flag.

from @Timple #391 (comment) :

The last working commit for Log messages was 81f8b08. Since 2381bf4 it's broken (PR #382).

This change has triggered the check in determine_field_mapping if fields are missing on both sides. Before this commit from @LoyVanBeek the early return skipped this check.

From @maum-meliora #391 (comment)

I think the issue is with the is_package_mapping() method in this code snippet from init.py:

This seems the be unrelated to #367. It was broken before that PR as well for custom mappings that also specify message names or fields mappings.
The check for the len(data) was to strict for is_package_mapping. Custom mappings that included message name or fields mapping keys where ignored. This lead to the Log message not being found as mapping pair.

I have a open WorkInProgress PR on our ros1_bridge fork that fixes both issues: mojin-robotics#21

What is missing is that the level constant values differ between ROS1 and ROS2, so at least rqt crashes if it sees an unknown (to ROS1) level value. But foxglove/lichtblick can handle this.

So we need custom mapping code like for std_msgs/Duration and std_msgs/Time in convert_builtin_interfaces.cpp to get this to work proper.