Skip to content

Commit

Permalink
Add python example
Browse files Browse the repository at this point in the history
* Refs #13459. Add Python getting started

Signed-off-by: Ricardo González Moreno <[email protected]>

* Refs #13459. Fix video

Signed-off-by: Ricardo González Moreno <[email protected]>

* Refs #13639. Fix tests

Signed-off-by: Ricardo González Moreno <[email protected]>

* Refs #13639. Fix warnings

Signed-off-by: Ricardo González Moreno <[email protected]>

* Apply suggestions from code review

Co-authored-by: jsantiago-eProsima <[email protected]>
Signed-off-by: Ricardo González Moreno <[email protected]>

* Apply suggestions from code review

Co-authored-by: jsantiago-eProsima <[email protected]>
Signed-off-by: Ricardo González Moreno <[email protected]>

* Apply suggestions from code review

Co-authored-by: jsantiago-eProsima <[email protected]>
Signed-off-by: Ricardo González Moreno <[email protected]>

* Refs #13639. Apply suggestions on C++ example

Signed-off-by: Ricardo González Moreno <[email protected]>

* Apply suggestions from code review

Co-authored-by: jsantiago-eProsima <[email protected]>
Signed-off-by: Ricardo González Moreno <[email protected]>

* Refs #13639. Fix error

Signed-off-by: Ricardo González Moreno <[email protected]>

* Refs #13639. Fix too long lines

Signed-off-by: Ricardo González Moreno <[email protected]>

Co-authored-by: jsantiago-eProsima <[email protected]>
  • Loading branch information
richiware and jsan-rt authored Feb 23, 2022
1 parent c460ae9 commit d7f2e0a
Show file tree
Hide file tree
Showing 20 changed files with 622 additions and 41 deletions.
114 changes: 114 additions & 0 deletions code/Examples/Python/HelloWorld/HelloWorldPublisher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
#
# 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.
"""
HelloWorld Publisher
"""
from threading import Condition
import time

import fastdds
import HelloWorld

DESCRIPTION = """HelloWorld Publisher example for Fast DDS python bindings"""
USAGE = ('python3 HelloWorldPublisher.py')

class WriterListener (fastdds.DataWriterListener) :
def __init__(self, writer) :
self._writer = writer
super().__init__()


def on_publication_matched(self, datawriter, info) :
if (0 < info.current_count_change) :
print ("Publisher matched subscriber {}".format(info.last_subscription_handle))
self._writer._cvDiscovery.acquire()
self._writer._matched_reader += 1
self._writer._cvDiscovery.notify()
self._writer._cvDiscovery.release()
else :
print ("Publisher unmatched subscriber {}".format(info.last_subscription_handle))
self._writer._cvDiscovery.acquire()
self._writer._matched_reader -= 1
self._writer._cvDiscovery.notify()
self._writer._cvDiscovery.release()


class Writer:


def __init__(self):
self._matched_reader = 0
self._cvDiscovery = Condition()
self.index = 0

factory = fastdds.DomainParticipantFactory.get_instance()
self.participant_qos = fastdds.DomainParticipantQos()
factory.get_default_participant_qos(self.participant_qos)
self.participant = factory.create_participant(0, self.participant_qos)

self.topic_data_type = HelloWorld.HelloWorldPubSubType()
self.topic_data_type.setName("HelloWorld")
self.type_support = fastdds.TypeSupport(self.topic_data_type)
self.participant.register_type(self.type_support)

self.topic_qos = fastdds.TopicQos()
self.participant.get_default_topic_qos(self.topic_qos)
self.topic = self.participant.create_topic("HelloWorldTopic", self.topic_data_type.getName(), self.topic_qos)

self.publisher_qos = fastdds.PublisherQos()
self.participant.get_default_publisher_qos(self.publisher_qos)
self.publisher = self.participant.create_publisher(self.publisher_qos)

self.listener = WriterListener(self)
self.writer_qos = fastdds.DataWriterQos()
self.publisher.get_default_datawriter_qos(self.writer_qos)
self.writer = self.publisher.create_datawriter(self.topic, self.writer_qos, self.listener)


def write(self):
data = HelloWorld.HelloWorld()
data.message("Hello World")
data.index(self.index)
self.writer.write(data)
print("Sending {message} : {index}".format(message=data.message(), index=data.index()))
self.index = self.index + 1


def wait_discovery(self) :
self._cvDiscovery.acquire()
print ("Writer is waiting discovery...")
self._cvDiscovery.wait_for(lambda : self._matched_reader != 0)
self._cvDiscovery.release()
print("Writer discovery finished...")


def run(self):
self.wait_discovery()
for x in range(10) :
time.sleep(1)
self.write()
self.delete()


def delete(self):
factory = fastdds.DomainParticipantFactory.get_instance()
self.participant.delete_contained_entities()
factory.delete_participant(self.participant)


if __name__ == '__main__':
print('Starting publisher.')
writer = Writer()
writer.run()
exit()
96 changes: 96 additions & 0 deletions code/Examples/Python/HelloWorld/HelloWorldSubscriber.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
#
# 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.
"""
HelloWorld Subscriber
"""
import signal

import fastdds
import HelloWorld

DESCRIPTION = """HelloWorld Subscriber example for Fast DDS python bindings"""
USAGE = ('python3 HelloWorldSubscriber.py')

# To capture ctrl+C
def signal_handler(sig, frame):
print('Interrupted!')

class ReaderListener(fastdds.DataReaderListener):


def __init__(self):
super().__init__()


def on_subscription_matched(self, datareader, info) :
if (0 < info.current_count_change) :
print ("Subscriber matched publisher {}".format(info.last_publication_handle))
else :
print ("Subscriber unmatched publisher {}".format(info.last_publication_handle))


def on_data_available(self, reader):
info = fastdds.SampleInfo()
data = HelloWorld.HelloWorld()
reader.take_next_sample(data, info)

print("Received {message} : {index}".format(message=data.message(), index=data.index()))


class Reader:


def __init__(self):
factory = fastdds.DomainParticipantFactory.get_instance()
self.participant_qos = fastdds.DomainParticipantQos()
factory.get_default_participant_qos(self.participant_qos)
self.participant = factory.create_participant(0, self.participant_qos)

self.topic_data_type = HelloWorld.HelloWorldPubSubType()
self.topic_data_type.setName("HelloWorld")
self.type_support = fastdds.TypeSupport(self.topic_data_type)
self.participant.register_type(self.type_support)

self.topic_qos = fastdds.TopicQos()
self.participant.get_default_topic_qos(self.topic_qos)
self.topic = self.participant.create_topic("HelloWorldTopic", self.topic_data_type.getName(), self.topic_qos)

self.subscriber_qos = fastdds.SubscriberQos()
self.participant.get_default_subscriber_qos(self.subscriber_qos)
self.subscriber = self.participant.create_subscriber(self.subscriber_qos)

self.listener = ReaderListener()
self.reader_qos = fastdds.DataReaderQos()
self.subscriber.get_default_datareader_qos(self.reader_qos)
self.reader = self.subscriber.create_datareader(self.topic, self.reader_qos, self.listener)


def delete(self):
factory = fastdds.DomainParticipantFactory.get_instance()
self.participant.delete_contained_entities()
factory.delete_participant(self.participant)


def run(self):
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C to stop')
signal.pause()
self.delete()


if __name__ == '__main__':
print('Creating subscriber.')
reader = Reader()
reader.run()
exit()
11 changes: 11 additions & 0 deletions docs/03-exports/aliases-python.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.. |DataReaderListener::on_data_available-python-api| replace:: :py:func:`on_data_available()<fastdds.DataReaderListener.on_data_available>`
.. |DataReaderListener::on_subscription_matched-python-api| replace:: :py:func:`on_subscription_matched()<fastdds.DataReaderListener.on_subscription_matched>`

.. |DataWriterListener-python-api| replace:: :py:class:`DataWriterListener<fastdds.DataWriterListener>`
.. |DataWriterListener::on_publication_matched-python-api| replace:: :py:func:`on_publication_matched()<fastdds.DataWriterListener.on_publication_matched>`

.. |DomainParticipantFactory-python-api| replace:: :py:class:`DomainParticipantFactory<fastdds.DomainParticipantFactory>`

.. |MatchedStatus-python-api| replace:: :py:class:`MatchedStatus<fastdds.MatchedStatus>`

.. |SampleInfo-python-api| replace:: :py:class:`SampleInfo<fastdds.SampleInfo>`
Binary file added docs/_static/simple_python_pubsub.mp4
Binary file not shown.
1 change: 1 addition & 0 deletions docs/fastdds/getting_started/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ application.

definitions
simple_app/simple_app
simple_python_app/simple_python_app
4 changes: 2 additions & 2 deletions docs/fastdds/getting_started/simple_app/includes/dataType.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Build the topic data type
^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^

*eProsima Fast DDS-Gen* is a Java application that generates source code using the data types defined in an
Interface Description Language (IDL) file. This application can do two different things:
Expand All @@ -20,7 +20,7 @@ In the workspace directory, execute the following commands:
cd src && touch HelloWorld.idl
This creates the HelloWorld.idl file in the `src` directory.
Open the file in your favorite text editor and copy and paste the following snippet of code.
Open the file in a text editor and copy and paste the following snippet of code.

.. code-block:: idl
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Import linked libraries and its dependencies
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The DDS application requires the Fast DDS and Fast CDR libraries.
The way we will make these accessible from the
workspace depends on the installation procedure we have followed in the Installation Manual.
Depending on the installation procedure followed the process of making these libraries available for our DDS application
will be slightly different.

Installation from binaries and manual installation
""""""""""""""""""""""""""""""""""""""""""""""""""
Expand All @@ -17,16 +17,18 @@ the directory `/usr/lib/`.
Colcon installation
"""""""""""""""""""

If you have followed the Colcon installation there are several ways to import the libraries.
If you want these to be accessible only from the current shell session, run one of the following two commands.
From a Colcon installation there are several ways to import the libraries.
If the libraries need to be available just for the current session, run the following command.

.. code-block:: bash
source <path/to/Fast-DDS/workspace>/install/setup.bash
If you want these to be accessible from any session, you can add the Fast DDS installation directory to your ``$PATH``
variable in the shell configuration files running the following command.
They can be made accessible from any session by adding the Fast DDS installation directory to your ``$PATH``
variable in the shell configuration files for the current user running the following command.

.. code-block:: bash
echo 'source <path/to/Fast-DDS/workspace>/install/setup.bash' >> ~/.bashrc
This will set up the environment after each of this user's logins.
21 changes: 10 additions & 11 deletions docs/fastdds/getting_started/simple_app/includes/publisher.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ From the `src` directory in the workspace, run the following command to download
wget -O HelloWorldPublisher.cpp \
https://raw.githubusercontent.com/eProsima/Fast-RTPS-docs/master/code/Examples/C++/DDSHelloWorld/src/HelloWorldPublisher.cpp
Now you have the publisher's source code. The publisher is going to send 10 publications under the topic HelloWorld.
This is the C++ source code for the publisher application.
It is going to send 10 publications under the topic `HelloWorldTopic`.

.. literalinclude:: /../code/Examples/C++/DDSHelloWorld/src/HelloWorldPublisher.cpp
:language: C++
Expand Down Expand Up @@ -79,16 +80,14 @@ in the DomainParticipant.
:lines: 33-45

Then, the :class:`PubListener` class is defined by inheriting from the |DataWriterListener-api| class.
This class overrides the default DataWriter listener callbacks, which allow us to execute routines in case of an event.
The overridden callback
:cpp:func:`on_publication_matched <eprosima::fastdds::dds::DataWriterListener::on_publication_matched>`
allows you to define a series of actions when a new DataReader
This class overrides the default DataWriter listener callbacks, which allows the execution of routines in case of an
event.
The overridden callback |DataWriterListener::on_publication_matched-api|
allows the definition of a series of actions when a new DataReader
is detected listening to the topic under which the DataWriter is publishing.
The :func:`info.current_count_change` detects these changes of DataReaders that are matched to the
DataWriter.
This is a member in the
:cpp:struct:`MatchedStatus <eprosima::fastdds::dds::MatchedStatus>` structure that allows you to track changes in the
status of subscriptions.
This is a member in the |MatchedStatus-api| structure that allows tracking changes in the status of subscriptions.
Finally, the ``listener_`` object of the class is defined as an instance of :class:`PubListener`.


Expand Down Expand Up @@ -141,7 +140,7 @@ This is simply the `writing` of a change by the DataWriter object.
:lines: 157-167
:dedent: 4

The public run function executes the action of publishing a given number of times, waiting for 1 second between
The public *run* function executes the action of publishing a given number of times, waiting for 1 second between
publications.

.. literalinclude:: /../code/Examples/C++/DDSHelloWorld/src/HelloWorldPublisher.cpp
Expand All @@ -165,8 +164,8 @@ files needed to build the executable, and links the executable and the library t
:language: bash
:lines: 47-48

At this point you can build, compile and run the publisher application. From the build directory in the workspace, run
the following commands.
At this point the project is ready for building, compiling and running the publisher application.
From the build directory in the workspace, run the following commands.

.. code-block:: bash
Expand Down
25 changes: 11 additions & 14 deletions docs/fastdds/getting_started/simple_app/includes/subscriber.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ From the `src` directory in the workspace, execute the following command to down
wget -O HelloWorldSubscriber.cpp \
https://raw.githubusercontent.com/eProsima/Fast-RTPS-docs/master/code/Examples/C++/DDSHelloWorld/src/HelloWorldSubscriber.cpp
Now you have the subscriber's source code. The application runs a subscriber until it receives 10 samples under the
topic HelloWorldTopic. At this point the subscriber stops.
This is the C++ source code for the subscriber application.
The application runs a subscriber until it receives 10 samples under the topic `HelloWorldTopic`.
At this point the subscriber stops.

.. literalinclude:: /../code/Examples/C++/DDSHelloWorld/src/HelloWorldSubscriber.cpp
:language: C++
Expand All @@ -18,11 +19,10 @@ topic HelloWorldTopic. At this point the subscriber stops.
Examining the code
""""""""""""""""""

As you have noticed, the source code to implement the subscriber is practically identical to the source code implemented
by the publisher.
Therefore, we will focus on the main differences between them, without explaining all the code again.
Since the source code of both the publisher and subscriber applications is mostly identical, this document will focus
on the main differences between them, omitting the parts of the code that have already been explained.

Following the same structure as in the publisher explanation, we start with the includes of the C++ header files.
Following the same structure as in the publisher explanation, the first step is the includes of the C++ header files.
In these, the files that include the publisher class are replaced by the subscriber class and the data writer class by
the data reader class.

Expand Down Expand Up @@ -55,18 +55,15 @@ The private data members of the class will be the participant, the subscriber, t
data type.
As it was the case with the data writer, the listener implements the callbacks to be executed in case an event
occurs.
The first overridden callback of the SubListener is the
:cpp:func:`on_subscription_matched <eprosima::fastdds::dds::DataReaderListener::on_subscription_matched>`, which is the
analog of the :cpp:func:`on_publication_matched <eprosima::fastdds::dds::DataWriterListener::on_publication_matched>`
callback of the DataWriter.
The first overridden callback of the SubListener is the |DataReaderListener::on_subscription_matched-api|, which is the
analog of the |DataWriterListener::on_publication_matched-api| callback of the DataWriter.

.. literalinclude:: /../code/Examples/C++/DDSHelloWorld/src/HelloWorldSubscriber.cpp
:language: C++
:lines: 60-77
:dedent: 8

The second overridden callback is
:cpp:func:`on_data_available <eprosima::fastdds::dds::DataReaderListener::on_data_available>`.
The second overridden callback is |DataReaderListener::on_data_available-api|.
In this, the next received sample that the data reader can access is taken and processed to display its content.
It is here that the object of the |SampleInfo-api| class is defined, which determines whether a sample has already
been read or taken.
Expand All @@ -84,7 +81,7 @@ The public constructor and destructor of the class is defined below.
:lines: 102-126
:dedent: 4

Then we have the subscriber initialization public member function.
Next comes the subscriber initialization public member function.
This is the same as the initialization public member function defined for the :class:`HelloWorldPublisher`.
The QoS configuration for all entities, except for the participant's name, is the default QoS
(|PARTICIPANT_QOS_DEFAULT-api|, |SUBSCRIBER_QOS_DEFAULT-api|, |TOPIC_QOS_DEFAULT-api|, |DATAREADER_QOS_DEFAULT-api|).
Expand Down Expand Up @@ -122,7 +119,7 @@ files needed to build the executable, and links the executable and the library t
:language: bash
:lines: 50-51

At this point you can build, compile and run the subscriber application.
At this point the project is ready for building, compiling and running the subscriber application.
From the build directory in the workspace, run the following commands.

.. code-block:: bash
Expand Down
Loading

0 comments on commit d7f2e0a

Please sign in to comment.