Skip to content

Commit

Permalink
Merge branch '11-list-and-detail-template' into 'master'
Browse files Browse the repository at this point in the history
Resolve "List and detail template"

Closes #11

See merge request anthony.remazeilles/ros_pkg_gen!15
  • Loading branch information
aremazeilles committed Feb 14, 2020
2 parents 7ad4a7e + a7e4a67 commit d40f673
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 126 deletions.
28 changes: 12 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ To do so the input needed are:
* An _interface specification_: a xml file describing mainly the interface of the package to create, according to the template.
This file is to be filled by the _Developer_, using the interface proposed by the template, according to the concrete needs of the package he is willing to create

**Author**: Anthony Remazeilles

**Maintainer**: Anthony Remazeilles, [email protected]
**Author & Maintainer**: Anthony Remazeilles, [email protected]

**Affiliation** : Tecnalia Research and Innovation, Spain

Expand Down Expand Up @@ -93,27 +91,25 @@ rosrun package_generator generate_package my_new_package_spec.ros_package
# open the generated package to insert the node logic.
```

The expected content of the xml file `my_new_package_spec.ros_package` and the behaviour of the generated code is described in [template package readme][template_readme].
The expected content of the xml file `my_new_package_spec.ros_package` and
the behaviour of the generated code is described in [template package readme][template_readme].
Please take 5 minutes to read it.
The script `generate_xml_skel` provides the interface file skeleton that the Developer as to adjust based on his needs.
The script `generate_xml_skel` provides the interface file skeleton
that the Developer as to adjust based on his needs.

The template name is corresponding to the template folder name within the [package_generator_templates](package_generator_templates/templates).
The possibility to indicate template located elsewhere will be soon resumed.
The template name is corresponding to the template folder name within the
[package_generator_templates](package_generator_templates/templates).
Option for indicating template located elsewhere will be soon resumed.

[template_readme]: package_generator_templates/README.md

## Content

### `package_generator`

Generates a node / package content based on a xml description.

See the dedicated [README](package_generator/README.md) for more details on its content.

### `package_generator_templates`
* [`package_generator`](package_generator/README.md):
generates a package content based on a xml description.

Gathers the package templates currently defined.
More details in the dedicated [Readme file](package_generator_templates/README.md)
* [`package_generator_templates`](package_generator_templates/README.md):
list of available package templates.

## Reminders

Expand Down
118 changes: 8 additions & 110 deletions package_generator_templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

This package gathers templates proposed for the `package_generator`.

**Author**: Anthony Remazeilles

**Maintainer**: Anthony Remazeilles, [email protected]
**Author & Maintainer**: Anthony Remazeilles, [email protected]

**Affiliation**: Tecnalia Research and Innovation, Spain

Expand All @@ -13,18 +11,9 @@ See [LICENSE.md](../LICENSE.md) for more details.

## Getting Started

### Prerequisites

The component is assuming `ROS` is installed on the machine.

### Installing

The installation procedure follows the standard operations as any ROS package does.

### Use

This package is mainly a wrapper to ease the access to the different templates.
It is mainly used through the [package_generator](../README.md).
This package is a ROS wrapper to ease the access to the different templates by the [package_generator](../README.md).

As detailed there, when the code generation is launched,

Expand All @@ -33,7 +22,7 @@ rosrun package_generator generate_package my_new_package_spec.ros_package
```

a tag is searched in the xml specification file `my_new_package_spec.ros_package` that specifies the template to be used.
Its value refers to a template supposed to be present in the [templates](templates) directory of this package.
Its value is the name of the template folder within the [templates](templates) directory of this package.

### Content

Expand All @@ -42,107 +31,16 @@ Its value refers to a template supposed to be present in the [templates](templat

### Available templates

* `cpp_node_update`: C++ node handling at a given frequency incoming messages (subscription) for generating and sending result messages.
* [cpp_node_update](templates/cpp_node_update/README.md): C++ node handling at a given frequency incoming messages (subscription) for generating and sending result messages.
Also gives access to all ROS interface.
* `python_node_update`: similar life-cycle for python.
* `cpp_service_server`: C++ node acting as a service server.
* `python_node_update`: similar life-cycle for python (see previous description).
* [cpp_service_server](templates/cpp_service_server/README.md): C++ node acting as a service server.
* `python_service_server`: similar life-cycle for python.
* `msg_srv_action`: Basic layers for creating an interface package

## The `{cpp|python}_node_update` patterns

Both are jointly detailed since they both refer to the same node pattern.

They both generate nodes in which incoming messages (through subscription) are processed at a given frequency, and resulting in out-coming messages (through publication) sent at the same frequency.

If the pattern mainly restricts the node update policy for the publish /subscribe mechanism, it also enables to use _any_ of the other ROS communication means (i.e actions, services, tf).

The ROS interface and the core node intelligence are explicitly separated:

* In the C++ version, the ROS interface is in `ros/src/[node_name]_ros.cpp`, and the node implementation is in `common/src/[node_name]_common.cpp`
* In the python version, the ROS interface is in `src/[package_name]/[node_name]_ros.py`, and the implementation in `src/[package_name]/[node_name]_impl.py`
* The ROS interface class handles the creation of all needed ROS interface.
* You **should** only complete the node implementation files.

### Implementation file

The files `common/src/[node_name]_common.cpp` (C++) or `src/[package_name]/[node_name]_impl.py` (python) need to be filled by the Developer.

It contains different classes automatically created:

| Class | Description |
| ----- | ----------- |
| `[NodeName]Config` | contains parameter variables (read from `rosparam` or dynamically adjusted) |
| `[NodeName]Data` | contains the received messages and the messages to send |
| `[NodeName]Passthrough` | gathers ROS interface components _violating_ the interface / implementation paradigm (such as topic management out of the update concept, actions, ...) |
| `[NodeName]Impl` | contains the Developer implementation of the node |

**Only** class `[NodeName]Impl` should be modified.
It is provided with two methods (described from the C++ pattern):

| Method | Description |
| ------ | ----------- |
| `void configure([NodeName]Config config)` | enables to initialize the object given the configuration parameters contained in `config` |
| `void update([NodeName]Data &data, [NodeName]Config config)` | `data` contains the latest messages received by the ROS interface. The Developer should put in that same object the messages to be sent to the ROS world after the `update` method call. Parameter variables are accessible with object `config`|

The method `update` is called through the ROS file at the frequency specified by the Developer in the xml spec (see next section).

## Package & Nodes specification

The package and nodes are described by their interface.
This interface is defined in a `xml` file, following the syntax presented in this example.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<package name="py_dummy_package" author="anthony" author_email="[email protected]" description="Dummy package containing various interface" license="TODO">
<component name="first_node" frequency="50.0">
<publisher name="is_config_changed" type="std_msgs::Bool" description="Inform whether the config changed"/>
<publisher name="complete_name" type="std_msgs::String" description="name and surname"/>
<subscriber name="sub_surname" type="std_msgs::String" description="to receive the person surname"/>
<serviceServer name="srv_display_name" type="std_srvs::SetBool" description="to print the name"/>
<parameter name="name" type="std::string" value="Empty" description="default person name"/>
<parameter name="generate_mail_format" type="bool" value="1" description="whether mail format is used or not"/>
<actionServer name="count_char" type="actionlib::Test" description="count the letters in the generated name"/>
</component>
<depend>std_msgs</depend>
<depend>std_srvs</depend>
<depend>actionlib</depend>
</package>
```

All accepted (and required) attributes of a package tag are presented in the previous example.

A node is described by the attributes `name` and `frequency` (the update frequency, i.e the frequency of message subscription and publication).

Then is introduced the ROS interface provided by the node.
The current pattern provides the following interfaces:

* `publisher` and `subscriber` refer to the standard message publication and subscription.
Note that the access to received messages and the publication of messages is driven by the update frequency.
* `parameter` and `dynParameter` are parameters respectively obtained from `rosparam`, and the dynamical server.
At each update call, they will be provided to the node implementation.
* `serviceServer` and `serviceClient` refer to the management of ROS services.
Note that the service client is indicated to complete the node interface. Since the service can be directly called by the node implementation, its handler has been placed in `[NodeName]Passthrough`.
* `actionServer` and `actionClient`: Similarly, `actionServer` is defined in the `[NodeName]Passthrough` component, since the Developer may be willing to send action messages within the action callback.
* `listener` and `broadcaster`: informs the node will either listen to `tf` or publish transforms to `tf`.
Both variables are then available from the `[NodeName]Passthrough` component.
* `directSubscriber` and `directPublisher` are not handled through the update mechanism.
They are added to satisfy impatient Developers that consider they can not wait a period for receiving a message or sending another.
These components (implemented as traditional subscriber / publisher) are defined in the `[NodeName]Passthrough`.

More spec:

* All ROS interface tags are described by the attributes `name`, `type`, and `description`.
* The `name` should be in format `node_name`.
* The `type` should be using the c++ format as seen in the example.
* Only `parameter`, `listener` and `broadcaster` differ:
* For the `parameter`tag, accepted `type` are `{'std::string', 'string', 'int', 'double', 'bool'}`.
A default value is to be provided as well.
* For the `listener` and `broadcaster`, only attributes `name` and `description` are expected.
* [msg_srv_action](templates/msg_srv_action/README.md): Basic layers for creating an interface package

## Q & A

**_Where should I wrote my code?_**
**_Where should I write my code?_**

In the implementation file, anywhere and _only_ where special text indicates it.
In C++ files:
Expand Down
101 changes: 101 additions & 0 deletions package_generator_templates/templates/cpp_node_update/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# cpp_node_update

Template for a C++ node handling at a given frequency incoming messages
(subscription) for generating and sending result messages.

As the first template proposed, it also gives access to _all_ standard
ROS interfaces, i.e. topic subscription & publication, services, actions,
static & dynamic parameters, and tf.

## Pattern description

Both C++ and python versions follow the same pattern described here.

This template generates nodes in which incoming messages (through subscription)
are processed at a given frequency, and resulting in out-coming messages
(through publication) sent at the same frequency.

If the pattern mainly restricts the node update policy for the publish /subscribe mechanism, it also enables to use _any_ of the other ROS communication means (i.e actions, services, tf).

The ROS interface and the core node intelligence are explicitly separated:

* In the C++ version, the ROS interface is in `ros/src/[node_name]_ros.cpp`, and the node implementation is in `common/src/[node_name]_common.cpp`
* In the python version, the ROS interface is in `src/[package_name]/[node_name]_ros.py`, and the implementation in `src/[package_name]/[node_name]_impl.py`
* The ROS interface class handles the creation of all needed ROS interface.
* You **should** only complete the node implementation files.

### Implementation file

The files `common/src/[node_name]_common.cpp` (C++) or `src/[package_name]/[node_name]_impl.py` (python) need to be filled by the Developer.

It contains different classes automatically created:

| Class | Description |
| ----- | ----------- |
| `[NodeName]Config` | contains parameter variables (read from `rosparam` or dynamically adjusted) |
| `[NodeName]Data` | contains the received messages and the messages to send |
| `[NodeName]Passthrough` | gathers ROS interface components _violating_ the interface / implementation paradigm (such as topic management out of the update concept, actions, ...) |
| `[NodeName]Impl` | contains the Developer implementation of the node |

**Only** class `[NodeName]Impl` should be modified.
It is provided with two methods (described from the C++ pattern):

| Method | Description |
| ------ | ----------- |
| `void configure([NodeName]Config config)` | enables to initialize the object given the configuration parameters contained in `config` |
| `void update([NodeName]Data &data, [NodeName]Config config)` | `data` contains the latest messages received by the ROS interface. The Developer should put in that same object the messages to be sent to the ROS world after the `update` method call. Parameter variables are accessible with object `config`|

The method `update` is called through the ROS file at the frequency specified by the Developer in the xml spec (see next section).

## Package & Nodes specification

The package and nodes are described by their interface.
This interface is defined in a `xml` file, following the syntax presented in this example.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<package name="py_dummy_package" author="anthony" author_email="[email protected]" description="Dummy package containing various interface" license="TODO">
<component name="first_node" frequency="50.0">
<publisher name="is_config_changed" type="std_msgs::Bool" description="Inform whether the config changed"/>
<publisher name="complete_name" type="std_msgs::String" description="name and surname"/>
<subscriber name="sub_surname" type="std_msgs::String" description="to receive the person surname"/>
<serviceServer name="srv_display_name" type="std_srvs::SetBool" description="to print the name"/>
<parameter name="name" type="std::string" value="Empty" description="default person name"/>
<parameter name="generate_mail_format" type="bool" value="1" description="whether mail format is used or not"/>
<actionServer name="count_char" type="actionlib::Test" description="count the letters in the generated name"/>
</component>
<depend>std_msgs</depend>
<depend>std_srvs</depend>
<depend>actionlib</depend>
</package>
```

All accepted (and required) attributes of a package tag are presented in the previous example.

A node is described by the attributes `name` and `frequency` (the update frequency, i.e the frequency of message subscription and publication).

Then is introduced the ROS interface provided by the node.
The current pattern provides the following interfaces:

* `publisher` and `subscriber` refer to the standard message publication and subscription.
Note that the access to received messages and the publication of messages is driven by the update frequency.
* `parameter` and `dynParameter` are parameters respectively obtained from `rosparam`, and the dynamical server.
At each update call, they will be provided to the node implementation.
* `serviceServer` and `serviceClient` refer to the management of ROS services.
Note that the service client is indicated to complete the node interface. Since the service can be directly called by the node implementation, its handler has been placed in `[NodeName]Passthrough`.
* `actionServer` and `actionClient`: Similarly, `actionServer` is defined in the `[NodeName]Passthrough` component, since the Developer may be willing to send action messages within the action callback.
* `listener` and `broadcaster`: informs the node will either listen to `tf` or publish transforms to `tf`.
Both variables are then available from the `[NodeName]Passthrough` component.
* `directSubscriber` and `directPublisher` are not handled through the update mechanism.
They are added to satisfy impatient Developers that consider they can not wait a period for receiving a message or sending another.
These components (implemented as traditional subscriber / publisher) are defined in the `[NodeName]Passthrough`.

More spec:

* All ROS interface tags are described by the attributes `name`, `type`, and `description`.
* The `name` should be in format `node_name`.
* The `type` should be using the c++ format as seen in the example.
* Only `parameter`, `listener` and `broadcaster` differ:
* For the `parameter`tag, accepted `type` are `{'std::string', 'string', 'int', 'double', 'bool'}`.
A default value is to be provided as well.
* For the `listener` and `broadcaster`, only attributes `name` and `description` are expected.
25 changes: 25 additions & 0 deletions package_generator_templates/templates/cpp_service_server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# cpp_service_server

C++ node acting as a service server.

## Pattern description

Both C++ and python versions follow the same pattern described here.

Following the _separation of concern_,

* `ros/src/[nodename]_ros_.cpp`: implementation of the ROS interface.
* `common/src/[nodename]_common_.cpp`: implementation of the service callbacks.

The Developer should focus on the second file. It contains different classes automatically created:

| Class | Description |
| ----- | ----------- |
| `[NodeName]Config` | contains parameter variables (read from `rosparam` or dynamically adjusted) |
| `[NodeName]Passthrough` | gathers ROS components accessible for the services |
| `[NodeName]Impl` | contains the Developer implementation of the node |

Class `[NodeName]Impl` contains a constructor, and configure methods to be filled by the Developer.
It also contains a callback per service server defined by the Developer.

In class `[NodeName]Passthrough`, the Developer will have access to the transform listener and broadcaster, publisher, subscriber and service client he required access to.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# msg_srv_action

Template of a package that would contain message, action or service definition.
No code, just interface definition.

In the interface, the developer is asked to provide for any of these interface a name and a description.

The template will not create the message/service/action file.
It only prepares the CMakeLists.txt and package.xml file for the Developer.

0 comments on commit d40f673

Please sign in to comment.