-
Notifications
You must be signed in to change notification settings - Fork 84
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
[WIP] ROS 2 JSON publishing support #288
Conversation
ros2_babel_fish is not compatible with Iron, which needs a different implementation using new native rclcpp functionality
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if we could avoid having to copy all the babel fish code. The humble
release is currently blocked tho (see LOEWE-emergenCITY/ros_babel_fish#7). Maybe we could also avoid copying all that code with some git submodule / cmake magic?
In general, this approach (with babel fish) should also work for more recent distros (iron, rolling), right?
# Set clang*-15 as the default | ||
RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 100 | ||
RUN update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-15 100 | ||
RUN update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for preferring this over default clang install?
@@ -61,7 +68,7 @@ FoxgloveBridge::FoxgloveBridge(const rclcpp::NodeOptions& options) | |||
if (_useSimTime) { | |||
serverOptions.capabilities.push_back(foxglove::CAPABILITY_TIME); | |||
} | |||
serverOptions.supportedEncodings = {"cdr"}; | |||
serverOptions.supportedEncodings = {"cdr", "json"}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that should depend on ENABLE_JSON_MESSAGES
as well?
@@ -759,10 +759,11 @@ inline void Server<ServerConfiguration>::handleBinaryMessage(ConnHandle hdl, Mes | |||
length, | |||
data}; | |||
_handlers.clientMessageHandler(clientMessage, hdl); | |||
} catch (const ServiceError& e) { | |||
} catch (ServiceError const& e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does clang-format-15 introduce this change?
sendStatusAndLogMsg(hdl, StatusLevel::Error, e.what()); | ||
} catch (...) { | ||
sendStatusAndLogMsg(hdl, StatusLevel::Error, "callService: Failed to execute handler"); | ||
} catch (std::exception const& e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can theoretically throw anything (e.g. also throw 2
is valid) so I would leave the catch-all handler
@@ -10,7 +10,7 @@ ENV CC=clang | |||
ENV CXX=clang++ | |||
|
|||
# Set environment and working directory | |||
ENV ROS_WS /ros2_ws | |||
ENV ROS_WS /ros_ws |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we split all the dev environment changes out into a seperate PR?
#ifdef ENABLE_JSON_MESSAGES | ||
#include <ros2_babel_fish/babel_fish.hpp> | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since below we only have a pointer to the babel fish instance, we could move this include to the cpp file and replace it here with a forward declaration. However, there is probably no one (besides ros2_foxglove_bridge.cpp) that includes this file, so this is not something important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, forward declaration might be desirable. Altenrative, we can use the Pimpl idiom.
Just one additional question: in which cases will a user prefer to compile this with ENABLE_JSON_MESSAGES undefined?
#include "ros2_babel_fish/detail/babel_fish_action_client.hpp" | ||
#include "ros2_babel_fish/detail/babel_fish_publisher.hpp" | ||
#include "ros2_babel_fish/detail/babel_fish_service.hpp" | ||
#include "ros2_babel_fish/detail/babel_fish_service_client.hpp" | ||
#include "ros2_babel_fish/detail/babel_fish_subscription.hpp" | ||
#include "ros2_babel_fish/idl/type_support_provider.hpp" | ||
#include "ros2_babel_fish/messages/array_message.hpp" | ||
#include "ros2_babel_fish/messages/compound_message.hpp" | ||
#include "ros2_babel_fish/messages/value_message.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we weed out some of these that are not strictly required? E.g. I guess the action client could go
case MessageType::Array: { | ||
// Ensure the JSON value is an array | ||
if (!value.is_array()) { | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we throw an exception in that case?
nlohmann::json json; | ||
try { | ||
json = nlohmann::json::parse(jsonMessage); | ||
} catch (const nlohmann::json::parse_error& e) { | ||
return e; | ||
} | ||
|
||
// Convert the JSON message to a ROS message using ros2_babel_fish | ||
ros2_babel_fish::CompoundMessage::SharedPtr rosMsgPtr; | ||
try { | ||
rosMsgPtr = babelFish->create_message_shared(schemaName); | ||
} catch (const ros2_babel_fish::BabelFishException& e) { | ||
return e; | ||
} | ||
auto& rosMsg = *rosMsgPtr; | ||
for (const auto& key : rosMsg.keys()) { | ||
if (!json.contains(key)) { | ||
continue; | ||
} | ||
|
||
try { | ||
assignJsonToMessageField(rosMsg[key], json[key]); | ||
} catch (const std::exception& e) { | ||
return e; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's a lot of try-catch blocks. Having only one try-catch block should make it more readable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or related to my previous comment: Don't catch exceptions here and return the output message rather than the std::optional
auto babelFish = ros2_babel_fish::BabelFish::make_shared(); | ||
|
||
ros2_babel_fish::CompoundMessage::SharedPtr output; | ||
auto res = foxglove_bridge::jsonMessageToRos(payload, "std_msgs/msg/String", babelFish, output); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test for a more complex message type? E.g. geometry_msgs/PoseStamped
or something similar, ideally containing an array.
"Currently" is underselling it. Now that this module has been superseded by native ROS 2 API methods in Iron+, it is deprecated and will never be released.
My understanding is git submodules and cmake magic are generally frowned upon for ROS / ROS 2 projects that will be built and distributed in the ROS build system and third party developers. If you have a reference example in mind I can take a look.
No, babel fish does not build in Iron+ and has been replaced by API methods. It will require a different (albeit better) approach. |
The |
Just read this by chance and would like to say that it does in fact build in jazzy after some small changes addressing API changes. I'm also interested in the API methods that replace its functionality as I couldn't find anything about that. |
What is blocking this PR from being merged? @StefanFabian correct me if I am wrong, but ros2_bable_fish haven't been released as a package, right? Maybe we should start fixing that? |
No, it hasn't been released yet. |
Replaced by #307 |
Public-Facing Changes
cdr
. JSON payloads will be re-serialized tocdr
by the bridge before publishing to the ROS 2 graphDescription
This PR vendors in the unpublished https://github.com/LOEWE-emergenCITY/ros2_babel_fish library and uses it to support JSON message publishing from WebSocket clients. Incoming JSON messages are parsed, transformed into native ROS 2 messages field-by-field, then published to the ROS 2 graph.
TODO
{}
JSON message, simple message typesTime
/Duration
fields, etc