-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Examples of Zenoh applications communicating with ROS 2 Nodes | ||
|
||
This directory contains some examples of applications using the Zenoh APIs only (not ROS 2), and that can communicate with ROS 2 Nodes using CycloneDDS as RMW, via the `zenoh-bridge-ros2dds`. | ||
|
||
> :warning: The code of those examples are made to work with the version 0.10.x of the `zenoh-plugin-ros2dds` or `zenoh-bridge-ros2dds`. Soon both will be adapted for compatibility with the incoming `rmw_zenoh`, implying some code change in those examples. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Examples of Zenoh Python applications communicating with ROS 2 Nodes | ||
|
||
|
||
## Messages Publication: [talker.py](talker.py) | ||
|
||
This code mimics the ROS 2 [Topics "talker" demo](https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp/src/topics/talker.cpp). It's compatible with the ROS 2 [Topics "listener" demo](https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp/src/topics/listener.cpp) running those commands: | ||
- `ros2 run demo_nodes_cpp listener` | ||
- `zenho-bridge-ros2dds` | ||
- `python ./talker.py` | ||
|
||
## Messages Subscription: [listener.py](listener.py) | ||
|
||
This code mimics the ROS 2 [Topics "listener" demo](https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp/src/topics/listener.cpp). It's compatible with the ROS 2 [Topics "talker" demo](https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp/src/topics/talker.cpp) running those commands: | ||
- `ros2 run demo_nodes_cpp talker` | ||
- `zenho-bridge-ros2dds` | ||
- `python ./listener.py` | ||
|
||
## Services Client: [add_two_ints_client.py](add_two_ints_client.py) | ||
|
||
This code mimics the ROS 2 [Services "add_two_ints_client" demo](https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp/src/services/add_two_ints_client.cpp). It's compatible with the ROS 2 [Services "add_two_ints_server" demo](https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp/src/services/add_two_ints_server.cpp) running those commands: | ||
- `ros2 run demo_nodes_cpp add_two_ints_server` | ||
- `zenho-bridge-ros2dds` | ||
- `python ./add_two_ints_client.py` | ||
|
||
## Actions Client: [fibonnacci_action_client.py](fibonnacci_action_client.py) | ||
|
||
This code mimics the ROS 2 [Actions "fibonnacci_action_client" demo](https://github.com/ros2/demos/blob/rolling/action_tutorials/action_tutorials_cpp/src/fibonacci_action_client.cpp). It's compatible with the ROS 2 [Actions "fibonnacci_action_server" demo](https://github.com/ros2/demos/blob/rolling/action_tutorials/action_tutorials_cpp/src/fibonacci_action_server.cpp) running those commands: | ||
- `ros2 run action_tutorials_cpp fibonacci_action_server` | ||
- `zenho-bridge-ros2dds` | ||
- `python ./fibonnacci_action_client.py` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# | ||
# Copyright (c) 2024 ZettaScale Technology | ||
# | ||
# This program and the accompanying materials are made available under the | ||
# terms of the Eclipse Public License 2.0 which is available at | ||
# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
# which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
# | ||
# Contributors: | ||
# ZettaScale Zenoh Team, <[email protected]> | ||
# | ||
import time | ||
import argparse | ||
import zenoh | ||
|
||
# pycdr2 is the serializer of data in CDR format (required by ROS2) | ||
import pycdr2 | ||
from pycdr2 import IdlStruct | ||
from dataclasses import dataclass | ||
|
||
# Equivalent to AddTwoInts.Request class, but serializable by pycdr2 | ||
@dataclass | ||
class AddTwoInts_Request(IdlStruct, typename="AddTwoInts_Request"): | ||
a: pycdr2.types.int64 | ||
b: pycdr2.types.int64 | ||
|
||
# Equivalent to AddTwoInts.Response class, but serializable by pycdr2 | ||
@dataclass | ||
class AddTwoInts_Response(IdlStruct, typename="AddTwoInts_Request"): | ||
sum: pycdr2.types.int64 | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser( | ||
prog='add_two_ints_client', | ||
description='Zenoh/ROS2 add_two_ints_client example') | ||
parser.add_argument('--config', '-c', dest='config', | ||
metavar='FILE', | ||
type=str, | ||
help='A configuration file.') | ||
args = parser.parse_args() | ||
|
||
# Create Zenoh Config from file if provoded, or a default one otherwise | ||
conf = zenoh.Config.from_file(args.config) if args.config is not None else zenoh.Config() | ||
# Open Zenoh Session | ||
session = zenoh.open(conf) | ||
|
||
req = AddTwoInts_Request(a=2, b=3) | ||
# Send the query with the serialized request | ||
replies = session.get('add_two_ints', zenoh.Queue(), value=req.serialize()) | ||
# Zenoh could get several replies for a request (e.g. from several "Service Servers" using the same name) | ||
for reply in replies.receiver: | ||
# Deserialize the response | ||
rep = AddTwoInts_Response.deserialize(reply.ok.payload) | ||
print('Result of add_two_ints: %d' % rep.sum) | ||
|
||
session.close() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# | ||
# Copyright (c) 2024 ZettaScale Technology | ||
# | ||
# This program and the accompanying materials are made available under the | ||
# terms of the Eclipse Public License 2.0 which is available at | ||
# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
# which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
# | ||
# Contributors: | ||
# ZettaScale Zenoh Team, <[email protected]> | ||
# | ||
import time | ||
import argparse | ||
import zenoh | ||
|
||
# pycdr2 is the serializer of data in CDR format (required by ROS2) | ||
import pycdr2 | ||
from pycdr2 import IdlStruct | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass | ||
class Time(IdlStruct, typename="Time"): | ||
sec: pycdr2.types.uint32 | ||
nsec: pycdr2.types.uint32 | ||
|
||
# Equivalent to Fibonnaci.Goal.Request class, but serializable by pycdr2 | ||
@dataclass | ||
class Fibonacci_SendGoal_Request(IdlStruct, typename="Fibonacci_SendGoal_Request"): | ||
goal_id: pycdr2.types.array[pycdr2.types.uint8, 16] | ||
order: pycdr2.types.int32 | ||
|
||
# Equivalent to Fibonnaci.Goal.Response class, but serializable by pycdr2 | ||
@dataclass | ||
class Fibonacci_SendGoal_Response(IdlStruct, typename="Fibonacci_SendGoal_Response"): | ||
accepted: bool | ||
stamp: Time | ||
|
||
# Equivalent to Fibonnaci.Goal.Request class, but serializable by pycdr2 | ||
@dataclass | ||
class Fibonacci_GetResult_Request(IdlStruct, typename="Fibonacci_GetResult_Request"): | ||
goal_id: pycdr2.types.array[pycdr2.types.uint8, 16] | ||
|
||
# Equivalent to Fibonnaci.Goal.Response class, but serializable by pycdr2 | ||
@dataclass | ||
class Fibonacci_GetResult_Response(IdlStruct, typename="Fibonacci_GetResult_Response"): | ||
status: pycdr2.types.int8 | ||
sequence: pycdr2.types.sequence[pycdr2.types.int32] | ||
|
||
@dataclass | ||
class Fibonacci_Feedback(IdlStruct, typename="Fibonacci_Feedback"): | ||
goal_id: pycdr2.types.array[pycdr2.types.uint8, 16] | ||
partial_sequence: pycdr2.types.sequence[pycdr2.types.int32] | ||
|
||
|
||
|
||
|
||
def feedback_callback(sample: zenoh.Sample): | ||
# Deserialize the message | ||
feedback = Fibonacci_Feedback.deserialize(sample.payload) | ||
print('Received feedback: {0}'.format(feedback.partial_sequence)) | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser( | ||
prog='fibonacci_action_client', | ||
description='Zenoh/ROS2 fibonacci_action_client example') | ||
parser.add_argument('--config', '-c', dest='config', | ||
metavar='FILE', | ||
type=str, | ||
help='A configuration file.') | ||
args = parser.parse_args() | ||
|
||
# Create Zenoh Config from file if provoded, or a default one otherwise | ||
conf = zenoh.Config.from_file(args.config) if args.config is not None else zenoh.Config() | ||
# Open Zenoh Session | ||
session = zenoh.open(conf) | ||
|
||
# Declare a subscriber for feedbacks | ||
pub = session.declare_subscriber('fibonacci/_action/feedback', feedback_callback) | ||
|
||
goal_id = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] | ||
req = Fibonacci_SendGoal_Request(goal_id, order=10) | ||
# Send the query with the serialized request | ||
replies = session.get('fibonacci/_action/send_goal', zenoh.Queue(), value=req.serialize()) | ||
# Zenoh could get several replies for a request (e.g. from several "Service Servers" using the same name) | ||
for reply in replies.receiver: | ||
# Deserialize the response | ||
rep = Fibonacci_SendGoal_Response.deserialize(reply.ok.payload) | ||
if not rep.accepted: | ||
print('Goal rejected :(') | ||
return | ||
|
||
print('Goal accepted :)') | ||
|
||
req = Fibonacci_GetResult_Request(goal_id) | ||
# Send the query with the serialized request | ||
replies = session.get('fibonacci/_action/get_result', zenoh.Queue(), value=req.serialize()) | ||
# Zenoh could get several replies for a request (e.g. from several "Service Servers" using the same name) | ||
for reply in replies.receiver: | ||
# Deserialize the response | ||
rep = Fibonacci_GetResult_Response.deserialize(reply.ok.payload) | ||
print('Result: {0}'.format(rep.sequence)) | ||
|
||
|
||
session.close() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# | ||
# Copyright (c) 2024 ZettaScale Technology | ||
# | ||
# This program and the accompanying materials are made available under the | ||
# terms of the Eclipse Public License 2.0 which is available at | ||
# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
# which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
# | ||
# Contributors: | ||
# ZettaScale Zenoh Team, <[email protected]> | ||
# | ||
import time | ||
import argparse | ||
import zenoh | ||
|
||
# pycdr2 is the serializer of data in CDR format (required by ROS2) | ||
from pycdr2 import IdlStruct | ||
from dataclasses import dataclass | ||
|
||
# Equivalent to std_msgs.msg.String class, but serializable by pycdr2 | ||
@dataclass | ||
class String(IdlStruct, typename="String"): | ||
data: str | ||
|
||
def chatter_callback(sample: zenoh.Sample): | ||
# Deserialize the message | ||
msg = String.deserialize(sample.payload) | ||
print('I heard: [%s]' % msg.data) | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser( | ||
prog='listener', | ||
description='Zenoh/ROS2 listener example') | ||
parser.add_argument('--config', '-c', dest='config', | ||
metavar='FILE', | ||
type=str, | ||
help='A configuration file.') | ||
args = parser.parse_args() | ||
|
||
# Create Zenoh Config from file if provoded, or a default one otherwise | ||
conf = zenoh.Config.from_file(args.config) if args.config is not None else zenoh.Config() | ||
# Open Zenoh Session | ||
session = zenoh.open(conf) | ||
|
||
# Declare a subscriber | ||
pub = session.declare_subscriber('chatter', chatter_callback) | ||
|
||
try: | ||
while True: | ||
time.sleep(1) | ||
except (KeyboardInterrupt): | ||
pass | ||
finally: | ||
pub.undeclare() | ||
session.close() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# | ||
# Copyright (c) 2024 ZettaScale Technology | ||
# | ||
# This program and the accompanying materials are made available under the | ||
# terms of the Eclipse Public License 2.0 which is available at | ||
# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
# which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
# | ||
# Contributors: | ||
# ZettaScale Zenoh Team, <[email protected]> | ||
# | ||
import time | ||
import argparse | ||
import zenoh | ||
|
||
# pycdr2 is the serializer of data in CDR format (required by ROS2) | ||
from pycdr2 import IdlStruct | ||
from dataclasses import dataclass | ||
|
||
# Equivalent to std_msgs.msg.String class, but serializable by pycdr2 | ||
@dataclass | ||
class String(IdlStruct, typename="String"): | ||
data: str | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser( | ||
prog='talker', | ||
description='Zenoh/ROS2 talker example') | ||
parser.add_argument('--config', '-c', dest='config', | ||
metavar='FILE', | ||
type=str, | ||
help='A configuration file.') | ||
args = parser.parse_args() | ||
|
||
# Create Zenoh Config from file if provoded, or a default one otherwise | ||
conf = zenoh.Config.from_file(args.config) if args.config is not None else zenoh.Config() | ||
# Open Zenoh Session | ||
session = zenoh.open(conf) | ||
|
||
# Declare a publisher (optional but allows Zenoh to perform some optimizations) | ||
pub = session.declare_publisher('chatter') | ||
|
||
try: | ||
i = 0 | ||
while True: | ||
i += 1 | ||
msg = String(data='Hello World: {0}'.format(i)) | ||
print('Publishing: "{0}"'.format(msg.data)) | ||
# Publish the serialized message | ||
pub.put(msg.serialize()) | ||
time.sleep(1) | ||
|
||
except (KeyboardInterrupt): | ||
pass | ||
finally: | ||
pub.undeclare() | ||
session.close() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |