eclipse-zenoh / zenoh-plugin-ros1

Other
17 stars 9 forks source link

[Bug] can we pub a ROS topic and receive it in zenoh subscriber? #131

Open chenxin199305 opened 3 months ago

chenxin199305 commented 3 months ago

Describe the bug

When try the example:

# build the bridge from source
cargo build -p zenoh-bridge-ros1
cd target/debug/
# terminal 1:
./zenoh-bridge-ros1 --with_rosmaster true --ros_master_uri http://localhost:10000
# terminal 2:
./zenoh-bridge-ros1 --with_rosmaster true --ros_master_uri http://localhost:10001
# terminal 3:
ROS_MASTER_URI=http://localhost:10000 rostopic pub /topic std_msgs/String -r 1 test_message
# terminal 4:
ROS_MASTER_URI=http://localhost:10001 rostopic echo /topic

I can not find a way create a zenoh subscriber to listen to the middle zenoh message (using "topic" key). Is there a way to do it? or can you give an example?

To reproduce

as mentioned above.

System info

Ubuntu 20.04

edouard-fu commented 2 months ago

I've figured this one out from the source code of this ros1-zenoh bridge: the zenoh topic name has some prefixes. I've written the following code in python to convert a ros topic name to the corresponding zenoh topic name, using the rosbags python package:

def get_zenoh_name_of_ros1_topic(ros1_store, topic: str, msg_type: str) -> str:
        # Get md5 and encode msg_type to construct zenoh topic
        msg_type_split = msg_type.split('/')
        msg_type_encoded = '/'.join([msg_type_split[0],msg_type_split[2]]).encode('utf-8').hex()
        md5 = ros1_store.generate_msgdef(msg_type)[1]
        zenoh_topic = '/'.join([msg_type_encoded, md5, topic])

        return zenoh_topic

with a script example that uses this function:

from rosbags.typesys import Stores, get_typestore

ros1_store = get_typestore(Stores.ROS1_NOETIC)

zenoh_topic = get_zenoh_name_of_ros1_topic(ros1_store, topic="/my/poincloud/topic", msg_type="sensor_msgs/msg/PointCloud2")

My example is for the pointcloud2 type of message, but it also works for other standard ROS message definitions. However, note the difference in naming, it is "sensor_msgs/msg/PointCloud2" and NOT "sensor_msgs/PointCloud2".

You can now subscribe to the middle zenoh message with this generated topic name.

romainreignier commented 1 month ago

Thanks a lot @edouard-fu for the Python snippet. I had to add a little fix to remove the leading / on the topic name because the '/'.join() adds a second / which is not supported by Zenoh:

-         zenoh_topic = '/'.join([msg_type_encoded, md5, topic])
+         zenoh_topic = '/'.join([msg_type_encoded, md5, topic[1:]])

Using rosbags, I have added the deserialization to your example:

import zenoh, time
from rosbags.typesys import Stores, get_typestore

TOPIC = '/topic'
TYPE = 'std_msgs/msg/String'

def get_zenoh_name_of_ros1_topic(ros1_store, topic: str, msg_type: str) -> str:
    # Get md5 and encode msg_type to construct zenoh topic
    msg_type_split = msg_type.split('/')
    msg_type_encoded = '/'.join([msg_type_split[0],msg_type_split[2]]).encode('utf-8').hex()
    md5 = ros1_store.generate_msgdef(msg_type)[1]
    zenoh_topic = '/'.join([msg_type_encoded, md5, topic[1:]])

    return zenoh_topic

def listener(sample):
    msg = ros1_store.deserialize_ros1(sample.payload, TYPE)
    print(f'ROS1 msg: {msg.data}')

if __name__ == "__main__":
    session = zenoh.open(zenoh.Config())
    ros1_store = get_typestore(Stores.ROS1_NOETIC)
    zenoh_topic = get_zenoh_name_of_ros1_topic(ros1_store, topic=TOPIC, msg_type=TYPE)
    print(f'ROS topic {TOPIC} is converted to Zenoh {zenoh_topic}')
    sub = session.declare_subscriber(zenoh_topic, listener)
    time.sleep(60)
Carter12s commented 4 days ago

Just chiming in that this is still a usability problem, first day attempting to use Zenoh and this plugin and have been tripping over this for hours.

The examples: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/blob/main/zenoh-plugin-ros1/examples/ros1_sub.rs really make it look like this "should just work".

Would dearly love a config option like "No Mangle Names" or "Proxy Topics Unmangled" that would allow for this to work directly.