Contents
The Basics
Be Consistent
The important reason for having a style guide is to be consistent. This style guide can't cover every possible thing you may need to write a wiki page about, so just remember to be consistent in your own documentation.
If you invent a new style, remember that it has to be applied everywhere
There will be times where of a new way of formatting something that improves its readability, or you have to come up with some standard way of presenting something new. Remember though: if you come up with a new way of formatting a particular item, that formatting has to be applied to all occurrences of that item throughout the wiki (and documented here).
Common Names
Capitalization: the following are capitalized
The following are not capitalized:
Heading Levels
Pages: Start with heading-level 2 (i.e. ==). Heading 1 is reserved for the actual page title, which is automatically used
Heading level 5: Any heading level beyond level 4 gets more difficult to interpret. Consider other ways of formatting content. For an example of this, see Sample 1 and Sample 2 below.
Sample 1
BLTs
BLTs consist of three ingredients, which are discussed below.
Bacon
Bacon is delicious.
Lettuce
Lettuce is to make it healthy.
Tomato
Tomatoes bring out the red in the bacon.
Grilled Cheese
Now I will talk about my other favorite sandwich, the Grilled Cheese.
Sample 2
BLTs
BLTs consist of three ingredients, which are discussed below.
Bacon
- Bacon is delicious.
Lettuce
- Lettuce is to make it healthy.
Tomato
- Tomatoes bring out the red in the bacon.
Grilled Cheese
Now I will talk about my other favorite sandwich, the Grilled Cheese.
Code
Code Style Guides
There are existing code style guides for ROS packages:
Code API
Code API is generally done in Doxygen, Epydoc, or Sphinx. This documentation is automatically linked from the Wiki page for a ROS Package. While your wiki documentation can refer to the Code API, the comprehensive documentation should be done by the automatic generation capabilities of the language you are using. See rosdoc for more information.
Code (e.g. C++ classes, Python methods, etc...)
Example: Remember to invoke rospy.is_shutdown() regularly...
All code should be written in monospace using the backtick operator, e.g. `ros::Publisher`.
All methods should be clarified as method_calls() -- the parens operators make it very clear what you are referring to.
C++ class::Names
When referring to a C++ class, make it clear by including the namespace, e.g. my_package::Class, not Class.
You should only use C++ class names in your documentation when the documentation specifically applies to C++ classes. In other words, in general, do not use C++-style syntax when referring to:
Message types (e.g. sensor_msgs::LaserScan vs. sensor_msgs/LaserScan)
ROS concepts (e.g. ros::Publisher vs. publisher)
Python class names
The same rules apply as with C++ class names: include the module name when referring to a class, e.g. rospy.Publisher, so that it is clear that you are referring to the Python entity.
ROS
ROS Names
Example: Node foo publishes messages to the bar topic.
ROS names are monospace. This includes tf frames, parameter names, service names, topic names, etc...
ROS Message Types and Service Types
Example: The node receives sensor_msgs/LaserScan messages...
NOTE: be careful to distinguish between ROS Messages, i.e. the data, vs. ROS Message types, the format of the data.
When referring to message types, you should always use the MsgLink macro, e.g.
<<MsgLink(sensor_msgs/LaserScan)>>
produces the link, sensor_msgs/LaserScan.
Similarly, use the SrvLink macro for services, e.g.:
<<SrvLink(nav_msgs/GetMap)>>
Look here for macros: WikiMacros
ROS Concepts
Example: When working with ROS topics....
When referring to ROS concepts like topics, services, and Packages, it is generally good form to indicate to the reader that you are talking about the ROS-meaning of these terms. When you introduce these concepts in your text, use a "ROS" prefix . After you have introduced the concept, you can use it without the prefix (unless you need to disambiguate).
The reason we do this is that concepts like "package" have meaning in ROS, Java, Debian, Python, and many other places. This immediately clarifies to a reader who may have entered at your page.
ROS API
Each ROS node in your documentation needs to have ROS API documentation. To help make this consistent and allow us to make some stylistic changes in the future, we do this using the CS/NodeAPI clearsilver template.
Clearsilver uses a hierarchical data format called HDF.
Your node API ends up being specified in a consistent HDF representation inside a code block. The code block will always start with:
{{{ #!clearsilver CS/NodeAPI
In the event of a single node, you should specify HDF strings for the name and description of the node.
Additionally, the following sections can optionally be specified
sub - topics the node subscribes to
Expects sub-fields: name, type, desc
pub - topics the node publishes
Expects sub-fields: name, type, desc
srv - services the node provides
Expects sub-fields: name, type, desc
srv_called - services the node calls
Expects sub-fields: name, type, desc
param - parameters the node checks
Expects sub-fields: name, type, desc, default
param_set - parameters the node sets
Expects sub-fields: name, type, desc, default
req_tf - tf frames the node expects
Expects sub-fields: from, to, desc
prov_tf - tf frames the node provides
Expects sub-fields: from, to, desc
goal - action goal the node provides
Expects sub-fields: name, type, desc
feedback - action feedback the node provides
Expects sub-fields: name, type, desc
result - action result the node provides
Expects sub-fields: name, type, desc
act_called - actions the node calls
Expects sub-fields: name, type, desc
As a minimal example, the code:
{{{ #!clearsilver CS/NodeAPI name = my_node desc = does something interesting sub { 0.name = topic_name1 0.type = std_msgs/String 0.desc = it publishes this topic 1.name = topic_name2 1.type = std_msgs/String 1.desc = it also publishes to this topic } }}}
will produce the following:
my_node
does something interestingSubscribed Topics
topic_name1 (std_msgs/String)- it publishes this topic
- it also publishes to this topic
A full specification of all the possible sub-sections would look like:
{{{ #!clearsilver CS/NodeAPI name = node_name desc = does... sub { 0.name = foo/topic_name1 0.type = std_msgs/String 0.desc = topic_desciption 1 } pub { 0.name = foo/topic_name 0.type = std_msgs/String 0.desc = topic description, including any important rate information } srv { 0.name = foo/service_name 0.type = nav_msgs/GetMap 0.desc = service description } srv_called { 0.name = foo/service_name 0.type = nav_msgs/GetMap 0.desc = service description } param { 0.name = ~parameter_name 0.type = type 0.desc = parameter description 0.default = value } param_set { 0.name = ~parameter_name 0.type = type 0.desc = parameter description 0.default = value } req_tf { 0.from = foo 0.to = bar 0.desc = description of transform } prov_tf { 0.from = baz 0.to = mumble 0.desc = description of transform } }}}
And produce:
node_name
does...Subscribed Topics
foo/topic_name1 (std_msgs/String)- topic_desciption 1
Published Topics
foo/topic_name (std_msgs/String)- topic description, including any important rate information
Services
foo/service_name (nav_msgs/GetMap)- service description
Services Called
foo/service_name (nav_msgs/GetMap)- service description
Parameters
~parameter_name (type, default: value)- parameter description
Parameters Set
~parameter_name (type, default: value)- parameter description
Required tf Transforms
foo → bar- description of transform
Provided tf Transforms
baz → mumble- description of transform
Additionally, these variables can be pushed down into a variable called node, or, in the event of multiple nodes, an array, specified in HDF by node.0, node.1, etc.
== Nodes == {{{ #!clearsilver CS/NodeAPI node.0 { name = One node desc = ... } node.1 { name = Another Node desc = ... } }}}
Which produces:
Nodes
One node
...Another Node
...
Occasionally, it may be necessary to specify a list of one of the sub-sections without a node:
{{{ #!clearsilver CS/NodeAPI pub { 0.name = foo/topic_name1 0.type = std_msgs/String 0.desc = topic_desciption 1 } }}}
Or, to break up a sub-section into multiple groupings:
{{{ #!clearsilver CS/NodeAPI param { group.0 { 0.name = ~parameter_name 0.type = type 0.desc = parameter description 0.default = value } group.1 { name = DEPRECATED desc = description of parameters which should no longer be used. 0.name = ~old_parameter_name 0.type = type 0.desc = old parameter description 0.default = value } }}}
Which ends up looking like:
Parameters
~parameter_name (type, default: value)- parameter description
DEPRECATED
description of parameters which should no longer be used.- old parameter description
If you have a description that is long or requires multi-line formatting, HDF's heredoc syntax is useful:
{{{ #!clearsilver CS/NodeAPI #!clearsilver CS/NodeAPI param { 0.name = charles 0.type = string 0.default = dickens 0.desc << EOM It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to heaven, we were all going direct the other way - in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only. EOM } }}}
Which looks like:
Parameters
charles (string, default: dickens)- It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to heaven, we were all going direct the other way - in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.
The heading for a sub-section can be suppressed by no_header=True. One common use case: when maintaining a node's documentation over multiple ROS distros with the Version macro, some parameters (topics, etc) may only exist in certain distros. You could separate them as follows:
<<Version()>> {{{ #!clearsilver CS/NodeAPI param { 0.name = common_parameter 0.type = string 0.default = foo 0.desc = This parameter present in all versions. }}} {{{{#!wiki version indigo jade {{{ #!clearsilver CS/NodeAPI param { no_header=True 1.name = new_parameter 1.type = string 1.default = bar 1.desc = This parameter added in ROS Jade. }}} }}}}
Which looks like:
Show EOL distros:
Parameters
common_parameter (string, default: foo)- This parameter present in all versions.
new_parameter (string, default: bar)
- This parameter added in ROS Indigo.
For other examples of this, see the gmapping and image_transport packages.
Package/Stack Documentation
Linking to Trac Tickets
The TracLink macro lets you link into Trac tickets so that visitors can easily file tickets, e.g.:
<<TracLink(ros-pkg geometry)>>
Expands to: <<TracLink(ros-pkg geometry)>>
Thirdparty Packages
Thirdparty ROS Packages need documentation too. It is customary to include a "External Documentation" section, like the one below, so that users can quickly see that they should go elsewhere for proper documentation.
=== External Documentation === This is a third party package with [[http://www.continuousphysics.com/Bullet/BulletFull/index.html|external documentation]].
Files
Filenames
Filenames are monospace. In general, it's a good idea to specify filenames relative to the package they are in, e.g. roslaunch/example.launch.
Using external editors
If you do any significant amount of wiki editing, you will grow to hate the in-browser text box. Do yourself a favor and use your favorite text editor instead.
The simplest approach is to copy the text box content to your editor, make your changes, and copy back. Depending on your preferred browser, you may be able to streamline this:
Firefox: It's All Text! works nicely.
Chrome: No direct equivalent, but see http://superuser.com/questions/261689/its-all-text-for-chrome for suggestions.
Emacs
Follow the instructions at http://moinmo.in/EmacsForMoinMoin to install the handy MoinMoin editing mode. Make sure to install both moinmoin-mode.el and screen-lines.el.
If using It's All Text!, add .wiki in the “File Extensions” list in the preferences setting dialog. Then you can right-click the edit button and choose “Edit as '.wiki'”.