####################################
##FILL ME IN
####################################
## for a custom note with links:
## note =
## for the canned note of "This tutorial assumes that you have completed the
## previous tutorials:" just add the links
## note.0 = [[ROS/Tutorials | Beginner Tutorials]]
## descriptive title for the tutorial
## title = Writing Publisher/Subscriber with Parameters, Dynamic Reconfigure and Custom Messages (C++)
## multi-line description to be displayed in search
## description = This tutorial covers writing a publisher and a subscriber in C++. The use of custom messages and a publisher with a dynamic reconfigure server are covered.
## the next tutorial description (optional)
## !next =
## links to next tutorial (optional)
## next.0.link = [[ROSNodeTutorialC++Python | Using C++ and Python Nodes Together]]
## !next.1.link=
## what level user is this tutorial for
## level= IntermediateCategory
## keywords =
## parameter server, dynamic reconfigure, publisher, subscriber
####################################
<<IncludeCSTemplate(TutorialCSHeaderTemplate)>>

<<TableOfContents(4)>>

== Writing a Publisher/Subscriber with Dynamic Reconfigure and Parameter Server (C++) ==
This tutorial will show you how to combine several beginner level tutorials to create publisher and subscriber [[Nodes|nodes]] that are more fully-featured than the previously created nodes. This page will describe how to create a publisher node that:

 * Initializes several variables from either a launch file or using the command line by making use of the [[Parameter Server|parameter server]].
 * Makes several variables available to be modified during run-time using a [[dynamic_reconfigure|dynamic reconfigure server]].
 * Publishes data on a [[Topics|topic]] using [[Messages|custom messages]].

A subscriber node will be created to work with the publisher node that

 * Sets up a subscriber to listen for the custom message on the specified topic and prints out the message data.

The variables that are used, and the callback functions used by the publisher and subscriber, will be part of a class that is created for this purpose as described in [[roscpp_tutorials/Tutorials/UsingClassMethodsAsCallbacks|this tutorial]].

It is assumed that all of the [[ROS/Tutorials|beginner tutorials]] will have been completed before using this one.

=== How to Run Examples ===
There are two programs created here, very similar to what is found at the [[ROS/Tutorials/WritingPublisherSubscriber(c++)|ROS Publisher/Subscriber tutorial]]. They are even called the same names, {{{talker}}} and {{{listener}}}. If you haven't already checked out the code for this tutorial then you can get it into your home directory (represented as {{{~}}} in Unix-based systems) using

{{{#!sh
git clone https://github.com/tdenewiler/node_example.git
}}}
Make sure that the directory where you have the example code is in your {{{~/.bashrc}}} file under {{{ROS_PACKAGE_PATH}}}, similar to what is done when you [[diamondback/Installation/Ubuntu|install ROS]] initially. Assuming that {{{node_example}}} is checked out to your home directory you will need to add, near the bottom of your {{{~/.bashrc}}} file, the line

{{{
export ROS_PACKAGE_PATH=~/node_example:$ROS_PACKAGE_PATH
}}}
After adding that line either (i) restart terminal or (ii) run {{{source ~/.bashrc}}}. Those commands will both let the system know about this new environment variable and allow ROS to find the new node.

Then, make the example nodes using

{{{#!sh
cd ~/node_example
cmake .
rosmake
}}}
The command {{{cmake .}}} will create a {{{Makefile}}} and any other auto-generated code. The auto-generated code is in header files and is created when {{{rosbuild_genmsg()}}} and {{{gencfg()}}} are invoked from {{{CMakeLists.txt}}}. The rest of {{{rosmake}}} will generate the two nodes (binaries) that we will be running, both located in {{{~/node_example/bin/}}}. Using four terminals (or four tabs in a single terminal -- use <{{{ctrl-shift-t}}}> to start a new tab in an existing terminal, and <{{{alt-#}}}> to easily switch between tabs) run the following four commands.

{{{#!sh
roscore
rosrun node_example talker
rosrun node_example listener
rosrun rqt_reconfigure rqt_reconfigure
}}}
You should see output from the terminal running the {{{listener}}} node. If you change the {{{message}}} variable or either of the integer values in the {{{reconfigure_gui}}} then the output of {{{listener}}} should change to match it.

Alternatively, you can run everything using a launch file by running

{{{#!sh
roslaunch node_example c++_node_example.launch
}}}
The launch file starts {{{talker}}}, {{{listener}}}, {{{reconfigure_gui}}} and {{{rxconsole}}}. The output of {{{listener}}} will only appear in {{{rxconsole}}} and not in the terminal when using the launch file. See the [[rxconsole]] page for more details on how to use that tool.

The following sections go into more detail about how the nodes work.

=== Creating a Custom Message ===
[[ROS/Tutorials/CreatingMsgAndSrv|This tutorial]] describes messages in more detail. The custom message for these nodes contains

{{{#!sh
string message
int32 a
int32 b
}}}
After creating that file in the {{{msg/}}} directory and using {{{rosbuild_genmsg()}}} in {{{CMakeLists.txt}}} nothing else needs to be done for the custom message.

=== Creating Configuration for Dynamic Reconfigure Server ===
[[dynamic_reconfigure/Tutorials/SettingUpDynamicReconfigureForANode|This tutorial]] describes dynamic reconfigure in more detail. The variables available for use with the dynamic reconfigure server (that we will create later) are specified in the following file called {{{node_example_params.cfg}}} and located in the {{{cfg/}}} directory.

{{{#!python
#! /usr/bin/env python

PACKAGE='node_example'
import roslib
roslib.load_manifest(PACKAGE)

from dynamic_reconfigure.parameter_generator import *

gen = ParameterGenerator()
#       Name       Type      Level Description     Default Min   Max
gen.add("message", str_t,    0,    "The message.", "hello")
gen.add("a",       int_t,    0,    "First number.", 1,     -100, 100)
gen.add("b",       int_t,    0,    "First number.", 2,     -100, 100)

exit(gen.generate(PACKAGE, "node_example", "node_example_params"))
}}}
This means we will be able to modify a message and two integers. Eventually, we will be able to modify these values and see the results while our nodes are running. Make sure the file {{{node_example_params.cfg}}} is executable by doing

{{{#!sh
chmod 755 ~/node_example/cfg/node_example_params.cfg
}}}
Then, after using {{{gencfg()}}} in {{{CMakeLists.txt}}} we will have everything we need to use a dynamic reconfigure server.

== ROS Node Template ==
There are four files used to create the example nodes. There is one source and one header file that describe the class that is shared by {{{listener}}} and {{{talker}}}. Then, there is one source file to implement each of {{{listener}}} and {{{talker}}}. Note that the code style follows the [[CppStyleGuide|ROS C++ style guide]].

=== The talker node ===
The {{{node_example/src/talker.cpp}}} source file contains

{{{#!cplusplus
#include "node_example_core.h"

/*--------------------------------------------------------------------
 * main()
 * Main function to set up ROS node.
 *------------------------------------------------------------------*/

int main(int argc, char **argv)
{
  // Set up ROS.
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;

  // Create a new NodeExample object.
  NodeExample *node_example = new NodeExample();

  // Set up a dynamic reconfigure server.
  // This should be done before reading parameter server values.
  dynamic_reconfigure::Server<node_example::node_example_paramsConfig> dr_srv;
  dynamic_reconfigure::Server<node_example::node_example_paramsConfig>::CallbackType cb;
  cb = boost::bind(&NodeExample::configCallback, node_example, _1, _2);
  dr_srv.setCallback(cb);

  // Declare variables that can be modified by launch file or command line.
  int a;
  int b;
  string message;
  int rate;
  string topic;

  // Initialize node parameters from launch file or command line.
  // Use a private node handle so that multiple instances of the node can
  // be run simultaneously while using different parameters.
  // Parameters defined in the .cfg file do not need to be initialized here
  // as the dynamic_reconfigure::Server does this for you.
  ros::NodeHandle private_node_handle_("~");
  private_node_handle_.param("rate", rate, int(40));
  private_node_handle_.param("topic", topic, string("example"));

  // Create a publisher and name the topic.
  ros::Publisher pub_message = n.advertise<node_example::node_example_data>(topic.c_str(), 10);

  // Tell ROS how fast to run this node.
  ros::Rate r(rate);

  // Main loop.
  while (n.ok())
  {
    // Publish the message.
    node_example->publishMessage(&pub_message);

    ros::spinOnce();
    r.sleep();
  }

  return 0;
} // end main()
}}}
=== The listener node ===
The {{{node_example/src/listener.cpp}}} source file contains

{{{#!cplusplus
#include "node_example_core.h"

/*--------------------------------------------------------------------
 * main()
 * Main function to set up ROS node.
 *------------------------------------------------------------------*/

int main(int argc, char **argv)
{
  // Set up ROS.
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;

  // Declare variables that can be modified by launch file or command line.
  int rate;
  string topic;

  // Initialize node parameters from launch file or command line.
  // Use a private node handle so that multiple instances of the node can be run simultaneously
  // while using different parameters.
  ros::NodeHandle private_node_handle_("~");
  private_node_handle_.param("rate", rate, int(40));
  private_node_handle_.param("topic", topic, string("example"));

  // Create a new NodeExample object.
  NodeExample *node_example = new NodeExample();

  // Create a subscriber.
  // Name the topic, message queue, callback function with class name, and object containing callback function.
  ros::Subscriber sub_message = n.subscribe(topic.c_str(), 1000, &NodeExample::messageCallback, node_example);

  // Tell ROS how fast to run this node.
  ros::Rate r(rate);

  // Main loop.
  while (n.ok())
  {
    ros::spinOnce();
    r.sleep();
  }

  return 0;
} // end main()
}}}
=== The NodeExample class ===
The source file for the {{{node_example/src/node_example_core.cpp}}} class contains

{{{#!cplusplus
#include "node_example_core.h"

/*--------------------------------------------------------------------
 * NodeExample()
 * Constructor.
 *------------------------------------------------------------------*/

NodeExample::NodeExample()
{
} // end NodeExample()

/*--------------------------------------------------------------------
 * ~NodeExample()
 * Destructor.
 *------------------------------------------------------------------*/

NodeExample::~NodeExample()
{
} // end ~NodeExample()

/*--------------------------------------------------------------------
 * publishMessage()
 * Publish the message.
 *------------------------------------------------------------------*/

void NodeExample::publishMessage(ros::Publisher *pub_message)
{
  node_example::node_example_data msg;
  msg.message = message;
  msg.a = a;
  msg.b = b;

  pub_message->publish(msg);
} // end publishMessage()

/*--------------------------------------------------------------------
 * messageCallback()
 * Callback function for subscriber.
 *------------------------------------------------------------------*/

void NodeExample::messageCallback(const node_example::node_example_data::ConstPtr &msg)
{
  message = msg->message;
  a = msg->a;
  b = msg->b;

  // Note that these are only set to INFO so they will print to a terminal for example purposes.
  // Typically, they should be DEBUG.
  ROS_INFO("message is %s", message.c_str());
  ROS_INFO("sum of a + b = %d", a + b);
} // end publishCallback()

/*--------------------------------------------------------------------
 * configCallback()
 * Callback function for dynamic reconfigure server.
 *------------------------------------------------------------------*/

void NodeExample::configCallback(node_example::node_example_paramsConfig &config, uint32_t level)
{
  // Set class variables to new values. They should match what is input at the dynamic reconfigure GUI.
  message = config.message.c_str();
  a = config.a;
  b = config.b;
} // end configCallback()
}}}
=== The NodeExample header ===
The header file {{{node_example/include/node_example_core.h}}} for the class contains

{{{#!cplusplus
#ifndef SR_NODE_EXAMPLE_CORE_H
#define SR_NODE_EXAMPLE_CORE_H

// ROS includes.
#include "ros/ros.h"
#include "ros/time.h"

// Custom message includes. Auto-generated from msg/ directory.
#include "node_example/node_example_data.h"

// Dynamic reconfigure includes.
#include <dynamic_reconfigure/server.h>
// Auto-generated from cfg/ directory.
#include <node_example/node_example_paramsConfig.h>

using std::string;

class NodeExample
{
public:
  //! Constructor.
  NodeExample();

  //! Destructor.
  ~NodeExample();

  //! Callback function for dynamic reconfigure server.
  void configCallback(node_example::node_example_paramsConfig &config, uint32_t level);

  //! Publish the message.
  void publishMessage(ros::Publisher *pub_message);

  //! Callback function for subscriber.
  void messageCallback(const node_example::node_example_data::ConstPtr &msg);

  //! The actual message.
  string message;

  //! The first integer to use in addition.
  int a;

  //! The second integer to use in addition.
  int b;
};

#endif // SR_NODE_EXAMPLE_CORE_H
}}}
=== Building the code ===
After modifying the contents of {{{node_example/msg/node_example_data.msg}}} to add, remove or rename variables it is necessary to run

{{{#!sh
cd ~/node_example
cmake .
rosmake node_example
}}}
Invoking CMake again will auto-generate the new header files that contain information about the changes that were made to the message structure.

== Using Parameter Server and Dynamic Reconfigure ==
=== Parameter Server ===
There are several ways of setting variables to initial values through the use of the [[Parameter Server|parameter server]]. One is through a launch file, and another is from the command line.

In {{{node_example/c++_node_example.launch}}} the {{{talker}}} node is started with four parameters set, {{{message}}}, {{{a}}}, {{{b}}} and {{{rate}}}. To do the same thing from the command line {{{talker}}} could be started using

{{{#!sh
rosrun node_example talker _message:="Hello world!" _a:=57 _b:=-15 _rate:=1
}}}
Note that the {{{~}}} has been replaced by an underscore when modifying the private node handle parameters from the command line.

Then run

{{{#!sh
rosrun node_example listener
}}}
to see the differences.

Note that our nodes use [[roscpp/Overview/NodeHandles|private node handles]] for the parameter server. This is important because it helps to prevent name collisions when nodes are remapped to have unique node names. For instance, you may want to start two separate instances of a single node. With private node handles the separate nodes can have different values for the same parameter name. This comes in handy when you have multiple cameras of the same type but want to run them at different frame rates (this is just one example out of many for using private node handles).

=== Dynamic Reconfigure ===
The dynamic reconfigure tools are awesome, because they allow users to modify variable ''during'' runtime, not just at the start of runtime. We have already created a file specifying which variables are available to the dynamic reconfigure server. Note that the file {{{node_example/manifest.xml}}} has to have the line

{{{
<depend package="dynamic_reconfigure"/>
}}}
The {{{gencfg()}}} line in {{{CMakeLists.txt}}} causes the file {{{node_example/cfg/cpp/node_example/node_example_paramsConfig.h}}} to be auto-generated and this file is included in {{{node_example/include/node_example_core.h}}}.

== Review - What to Change ==
To use this example code as a new node you have to change several variables.

 1. Edit {{{manifest.xml}}} to depend on any other packages you need.
 1. Edit {{{CMakeLists.txt}}} to change the name of the executable(s) to build, and the source files that are used.
 1. Rename {{{cfg/node_example_params.cfg}}} to match the name of your node.
  * Change the {{{PACKAGE=}}} line to match the name of your node.
  * Change the last line to use the name of your node in the two places where {{{node_example}}} is present.
  * Modify the variables you make available to the dynamic reconfigure server.
 1. Rename {{{msg/node_example_data.msg}}} to match the name of your node.
  * Modify the variables you want in the new message.
 1. Rename {{{include/node_example_core.h}}}.
  * Modify the {{{#inlcude}}} lines to use your newly generated header files from the {{{.cfg}}} and {{{.msg}}} files.
  * Modify your class name, functions and variables.
 1. Rename {{{src/node_example_core.cpp}}}.
  * Use your new include file for your node.
  * Modify the class name, functions and variables.
 1. Modify {{{src/talker.cpp}}} or {{{src/listener.cpp}}}, rename them if you want.
  * Set up only the parts you want to use from the examples.
  * It is possible to combine initial configuration parameters, dynamic reconfigure server, publisher(s) and subscriber(s) all into a single node if desired.