Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ build:clang --linkopt="-fuse-ld=lld"
# Work around https://github.com/bazelbuild/rules_rust/issues/2125
build --action_env=CARGO_BAZEL_REPIN=1

common --enable_bzlmod --noenable_workspace
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this.


# Load any settings specific to the current user.
# user.bazelrc should appear in .gitignore so that settings are not shared with
# team members. This needs to be last statement in this config,
Expand Down
2 changes: 2 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ bazel_dep(name = "libyaml", version = "0.2.5")
bazel_dep(name = "lz4", version = "1.10.0.bcr.1")
bazel_dep(name = "nlohmann_json", version = "3.12.0.bcr.1")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "protobuf", version = "33.5")
bazel_dep(name = "pybind11_bazel", version = "3.0.0")
bazel_dep(name = "readerwriterqueue", version = "1.0.6")
bazel_dep(name = "rules_cc", version = "0.2.16")
Expand Down Expand Up @@ -150,6 +151,7 @@ use_repo(
"foxglove_bridge",
"iceoryx",
"osrf_pycommon",
"proto2ros",
"ros2",
"ros2_ament_index",
"ros2_class_loader",
Expand Down
4 changes: 4 additions & 0 deletions examples/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local_path_override(
path = "..",
)

bazel_dep(name = "protobuf", version = "33.5")
bazel_dep(name = "rules_cc", version = "0.2.9")
bazel_dep(name = "rules_python", version = "1.6.3")
bazel_dep(name = "rules_rust", version = "0.63.0")
Expand All @@ -29,6 +30,8 @@ rules_ros2_non_module_deps = use_extension("@com_github_mvukov_rules_ros2//ros2:
use_repo(
rules_ros2_non_module_deps,
# Check the rules_ros2 root MODULE.bazel for a full list of available non-module repos
# Required for proto2ros:
"proto2ros",
# Required for bazel test:
"ros2_common_interfaces",
"ros2_geometry2",
Expand All @@ -44,5 +47,6 @@ use_repo(
"ros2cli",
# Required for bazel run:
"ros2_rclpy",
# Required for proto2ros:
"ros2_rosidl",
)
59 changes: 59 additions & 0 deletions examples/proto_to_ros/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
load("@com_github_mvukov_rules_ros2//ros2:cc_defs.bzl", "ros2_cpp_binary")
load("@com_github_mvukov_rules_ros2//ros2:interfaces.bzl", "cpp_ros2_interface_library", "py_ros2_interface_library", "ros2_interface_library")
load("@com_github_mvukov_rules_ros2//ros2:launch.bzl", "ros2_launch")
load("@com_github_mvukov_rules_ros2//ros2:proto2ros.bzl", "proto2ros_message")
load("@protobuf//bazel:proto_library.bzl", "proto_library")
load("@rules_python//python:defs.bzl", "py_binary")

proto_library(
name = "chatter_proto",
srcs = ["message.proto"],
)

proto2ros_message(
name = "chatter_msgs",
msg_names = ["ChatterMessage"],
proto_library = ":chatter_proto",
)

ros2_interface_library(
name = "chatter_interfaces",
srcs = [":chatter_msgs"],
)

cpp_ros2_interface_library(
name = "chatter_interfaces_cpp",
deps = [":chatter_interfaces"],
)

py_ros2_interface_library(
name = "chatter_interfaces_py",
deps = [":chatter_interfaces"],
)

py_binary(
name = "talker",
srcs = ["talker.py"],
deps = [
":chatter_interfaces_py",
"@ros2_rclpy//:rclpy",
],
)

ros2_cpp_binary(
name = "listener",
srcs = ["listener.cc"],
deps = [
":chatter_interfaces_cpp",
"@ros2_rclcpp//:rclcpp",
],
)

ros2_launch(
name = "proto_to_ros",
launch_file = "proto_to_ros.py",
nodes = [
":listener",
":talker",
],
)
62 changes: 62 additions & 0 deletions examples/proto_to_ros/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Proto2ros Example

This example demonstrates how to use `proto2ros` to convert Protocol Buffer
definitions to ROS 2 messages, integrated with working ROS 2 nodes.

## Overview

The example shows:
- Converting a `.proto` file to ROS 2 `.msg` format
- Using the `proto2ros_message` rule
- **Python talker node** publishing messages on the `chatter` topic
- **C++ listener node** subscribing to messages on the `chatter` topic

## Files

- `message.proto` - Protocol Buffer message definition
- `talker.py` - Python publisher node
- `listener.cc` - C++ subscriber node
- `proto2ros.py` - Launch file to run both nodes
- `BUILD.bazel` - Bazel build configuration

## Usage

### In BUILD.bazel

```python
load("@protobuf//bazel:proto_library.bzl", "proto_library")
load("@com_github_mvukov_rules_ros2//ros2:proto2ros.bzl", "proto2ros_message")

proto_library(
name = "chatter_proto",
srcs = ["message.proto"],
)

proto2ros_message(
name = "chatter_msgs",
msg_names = ["ChatterMessage"],
proto_library = ":chatter_proto",
)

ros2_interface_library(
name = "chatter_interfaces",
srcs = [":chatter_msgs"],
)
```

### Building

```bash
bazel build //examples/proto_to_ros:all
bazel build //examples/proto_to_ros:talker # Python talker node
bazel build //examples/proto_to_ros:listener # C++ listener node
bazel build //examples/proto_to_ros:proto_to_ros # Launch file
```

### Running

Run the demo to see the Python talker and C++ listener communicate:

```bash
bazel run //examples/proto_to_ros:proto_to_ros
```
46 changes: 46 additions & 0 deletions examples/proto_to_ros/listener.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2026 Milan Vukov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>

#include "chatter_interfaces/msg/chatter_message.hpp"
#include "rclcpp/rclcpp.hpp"

/**
* C++ listener node using proto2ros generated messages.
*/
class ProtoChatterListener : public rclcpp::Node {
public:
ProtoChatterListener() : Node("proto_chatter_listener") {
subscription_ =
create_subscription<chatter_interfaces::msg::ChatterMessage>(
"chatter", 10,
[this](chatter_interfaces::msg::ChatterMessage::UniquePtr msg) {
RCLCPP_INFO(get_logger(),
"I heard: data='%s', timestamp=%ld",
msg->data.c_str(), msg->timestamp);
});
}

private:
rclcpp::Subscription<chatter_interfaces::msg::ChatterMessage>::SharedPtr
subscription_;
};

int main(int argc, char* argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<ProtoChatterListener>());
rclcpp::shutdown();
return 0;
}
8 changes: 8 additions & 0 deletions examples/proto_to_ros/message.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
syntax = "proto3";

package chatter;

message ChatterMessage {
string data = 1;
int64 timestamp = 2;
}
35 changes: 35 additions & 0 deletions examples/proto_to_ros/proto_to_ros.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2026 Milan Vukov
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Launch proto2ros chatter demo: Python talker and C++ listener."""

import launch
import launch_ros.actions


def generate_launch_description():
"""Launch a Python talker and C++ listener using proto2ros messages."""
return launch.LaunchDescription(
[
launch_ros.actions.Node(
executable="proto_to_ros/talker",
output="screen",
name="proto_talker",
),
launch_ros.actions.Node(
executable="proto_to_ros/listener",
output="screen",
name="proto_listener",
),
]
)
61 changes: 61 additions & 0 deletions examples/proto_to_ros/talker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright 2026 Milan Vukov
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Python talker node using proto2ros generated messages."""

import time

import rclpy
from chatter_interfaces.msg import ChatterMessage
from rclpy import node


class ProtoChatterTalker(node.Node):
"""Publishes ChatterMessage messages on the 'chatter' topic."""

def __init__(self):
super().__init__("proto_chatter_talker")
self.publisher_ = self.create_publisher(ChatterMessage, "chatter", 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0

def timer_callback(self):
"""Publish a ChatterMessage with data and timestamp."""
msg = ChatterMessage()
msg.data = f"Hello from proto2ros: {self.i}"
msg.timestamp = int(time.time() * 1000) # milliseconds since epoch
self.publisher_.publish(msg)
self.get_logger().info(
f'Publishing: data="{msg.data}", timestamp={msg.timestamp}'
)
self.i += 1


def main():
rclpy.init()

talker = ProtoChatterTalker()

try:
rclpy.spin(talker)
except KeyboardInterrupt:
pass
finally:
talker.destroy_node()
rclpy.shutdown()


if __name__ == "__main__":
main()
39 changes: 39 additions & 0 deletions repositories/proto2ros.BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Builds proto2ros from bdaiinstitute/proto2ros repository."""

load("@protobuf//bazel:py_proto_library.bzl", "py_proto_library")
load("@rules_python//python:defs.bzl", "py_binary", "py_library")
load("@rules_ros2_pip_deps//:requirements.bzl", "requirement")

py_proto_library(
name = "protobuf_runtime",
deps = ["@protobuf//:any_proto"],
)

# Core proto2ros Python library
py_library(
name = "proto2ros_lib",
srcs = glob(["proto2ros/proto2ros/**/*.py"]),
data = glob([
"proto2ros/proto2ros/configuration/*.yaml",
"proto2ros/proto2ros/output/templates/**/*",
]),
imports = ["proto2ros"],
deps = [
":protobuf_runtime",
"@ros2_rosidl//:rosidl_adapter_lib",
requirement("inflection"),
requirement("jinja2"),
requirement("networkx"),
requirement("numpy"),
requirement("pyyaml"),
],
)

# Main generation CLI binary
py_binary(
name = "generate",
srcs = ["proto2ros/proto2ros/cli/generate.py"],
main = "proto2ros/proto2ros/cli/generate.py",
visibility = ["//visibility:public"],
deps = [":proto2ros_lib"],
)
11 changes: 11 additions & 0 deletions repositories/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,14 @@ def ros2_repositories():
strip_prefix = "rcl_logging_syslog-e63257f2d5ca693f286bbcedf2b23720675b7f73",
urls = ["https://github.com/fujitatomoya/rcl_logging_syslog/archive/e63257f2d5ca693f286bbcedf2b23720675b7f73.zip"],
)

def proto2ros_repository():
"""Fetches proto2ros from GitHub."""
maybe(
http_archive,
name = "proto2ros",
build_file = "@com_github_mvukov_rules_ros2//repositories:proto2ros.BUILD.bazel",
sha256 = "31fbebb35056266f2959fda4291862f063b21ea29a8209c5d87cde49443e71bd",
strip_prefix = "proto2ros-0cc24714f99d1538d20fc25c9312d6199c3ce662",
url = "https://github.com/bdaiinstitute/proto2ros/archive/0cc24714f99d1538d20fc25c9312d6199c3ce662.tar.gz",
)
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
catkin_pkg
coverage
empy==3.3.*
inflection
jinja2
lark-parser
networkx
numpy~=1.23
packaging
psutil
Expand Down
Loading