Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode ROS2 raw byte data using rclpy.serialization.deserialize_message #1273

Open
EnzoGhisoni opened this issue Apr 22, 2024 · 3 comments
Open

Comments

@EnzoGhisoni
Copy link

EnzoGhisoni commented Apr 22, 2024

I try to get data from a ros-foxglove-bridge (more detail on the scope here
https://github.com/orgs/foxglove/discussions/991). I'm able to receive a ROS2 raw coded message in binary format but I'm not able to decode it properly. I tried to use deserialize_message to deserialize the data but I'm not able to make it work.

Required Info:

  • Operating System:
    • Ubuntu 22.04
  • Installation type:
    • Humble from binaries
  • DDS implementation:
    • rmw-cyclonedds
  • Client library (if applicable):
    • rclpy

Steps to reproduce issue

Here is a standalone code with only the data received from the websocket hardcoded. The original message is a ROS2 std_msgs.msg String at the format:

data: Hello, world! Time(nanoseconds=1713770713401001821, clock_type=ROS_TIME)

from std_msgs.msg import String
from rclpy.serialization import deserialize_message

# Serialized message data
serialized_data = b'\x01\x03\x00\x00\x00\xb3\xa8\xbfFb\x89\xc8\x17\x00\x01\x00\x00I\x00\x00\x00Hello, world! Time(nanoseconds=1713770713401001821, clock_type=ROS_TIME)\x00\x00\x00\x00'

def main():
    
    message_type = String()

    decoded_data = deserialize_message(serialized_data, message_type)
    print(decoded_data)

if __name__ == "__main__":
    main()

Expected behavior

I would like to be able to decode the string message to get a deserialized value (to be able to also decode more advanced message.

Actual behavior

It shows the following error message:
return _rclpy.rclpy_deserialize(serialized_message, message_type)
rclpy._rclpy_pybind11.RMWError: failed to deserialize ROS message: rmw_serialize: invalid data size, at ./src/rmw_node.cpp:1727

I'm not sure if I'm not able to use the function without error because of validity of my data or just because of the provided arguments.

@InvincibleRMC
Copy link
Contributor

I believe message_type = should be String not String()

@fujitatomoya
Copy link
Collaborator

serialized message seems to be wrong, the following works w/o any problem.

def main():
    msg = String()
    msg.data = 'Hello, world!'
    msg_serialized = serialize_message(msg)
    print(msg_serialized)
    msg_deserialized = deserialize_message(msg_serialized, String)
    print(msg_deserialized)

the output is,

b'\x00\x01\x00\x00\x0e\x00\x00\x00Hello, world!\x00'
std_msgs.msg.String(data='Hello, world!')

fujitatomoya added a commit to fujitatomoya/ros2_test_prover that referenced this issue May 3, 2024
@EnzoGhisoni
Copy link
Author

EnzoGhisoni commented May 4, 2024

I have tried what you suggest @fujitatomoya and I'm able to successfully decode the string, the issue is that my data come from foxglove_bridge and the encoding seems to be a bit different.

To give a bit more context, I try to create a ws-client to subscribe to a topic with a foxglove_bridge (https://github.com/foxglove/ros-foxglove-bridge), so I have:
ROS2 string publisher -> foxglove_bridge-> ws-client
The data copy pasted in the question is the string received from the foxglove_bridge.

Here is the complete python script of the ws-client:

import asyncio
import websockets
import json

from std_msgs.msg import String
from rclpy.serialization import deserialize_message

from mcap.reader import make_reader
from mcap_ros2.reader import read_ros2_messages
from mcap_ros2.decoder import DecoderFactory

async def handle_event(websocket, message, subscribed):
    # Handle different types of events here
    print("Received event:", message)
    
    if subscribed == False:
        
        subscribed = True
        subsriber = {
            "op": "subscribe",
            "subscriptions": [
                {"id": 3, "channelId": 3} # replace by the selected channel id the subscribe
            ]
        }
        await websocket.send(json.dumps(subsriber))
    
    if type(message) == bytes:
        print("Start to deserialize")
        message_type = String()

        # Decode the message here

        #decoded_data = deserialize_message(serialized_message=message, message_type=message_type)
        
        # print(decoded_data)

async def connect_to_server():
    uri = "ws://0.0.0.0:9090"  # Change this to your server URI
    subscribed = False
    async with websockets.connect(uri, subprotocols=["foxglove.websocket.v1"]) as websocket:
        print("Connected to server.")
        try:
            while True:
                message = await websocket.recv()
                
                await handle_event(websocket, message, subscribed)
                subscribed = True
        except websockets.ConnectionClosed:
            print("Connection to server closed.")

async def main():
    await connect_to_server()

if __name__ == "__main__":
    asyncio.run(main())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants