Connecting with ROS from NRP-Core Experiments¶
The implemented mechanism to interact with ROS from NRP-Core experiments is via ROS nodes in the Computational Graph (these nodes are a type of node in the graph, not to be confused with ROS nodes in the ROS architecture). This page describes how to define Computational Graphs in Python. And this page contains information on how to configure experiments to use a Computational Graph instead of Transceiver Functions.
Please notice, that in order to connect an NRP-Core experiment with ROS and being able to subscribe and publish to topics from the Computational Graph, the parameter ROSNode must be included in the experiment configuration (more information here).
A complete example experiment using Computational Graph ROS nodes can be found in the folder examples/event_loop_examples/husky_braitenberg_ros
in the nrp-core repository.
Finally, NRP-Core instantiates and stores C++ ROS message objects internally, but the Computational Graph is coded in Python and only those ROS message types for which compatible Python bindings has been generated can be used in experiments.
Below this line there is information on how to generate Python bindings for ROS message definitions so they can be used in NRP-Core experiments and some noticeable differences with the native ROS messages Python API.
Generating Python bindings for ROS messages¶
By default Python bindings are generated for all message types in the next ROS packages:
nrp_ros_msgs (package containing NRP-core ROS message definitions)
std_msgs
geometry_msgs
sensor_msgs
In order to generate Python bindings for ROS message types defined in other ROS packages, the names of the latter must be pass to cmake by defining the variable NRP_ROS_MSGS_PACKAGES
. Therefore, in order to generate Python bindings for new ROS messages it is needed to re-configure and build NRP-Core.
As an example, if you would like to use ROS msgs from the ROS packages navigation_msgs
and my_ros_package
in an NRP-Core experiments, NRP-Core should be configured with the command below:
cmake [other options] -DNRP_ROS_MSGS_PACKAGES=navigation_msgs;my_ros_package ..
The generated Python bindings can be found under the Pythonmodule nrp_core.data.nrp_ros
. E.g.
from nrp_core.data.nrp_ros.navigation_msgs import Path p = Path()
If any of the packages listed in NRP_ROS_MSGS_PACKAGES
does not exist in the ROS environment, there will be a cmake error.
API differences between native Python ROS messages and generated Python bindings¶
The generated binding classes match the original ROS Python API with only one exception. In ROS Python, fields of type array
are stored in objects of type list
while in the case of the Python binding generated by NRP-core a new class is created for each array field
. To illustrate the former, consider the case of UInt64MultiArray
message defined in the std_msgs
package:
# msg definition in std_msgs package MultiArrayLayout layout # specification of data layout uint64[] data # array of data
In ROS Python the field data
is stored in a list
, while in the NRP-core Python wrapper class it is stored in a new Python class of type UInt64MultiArray_data
:
import nrp_core.data.nrp_ros.std_msgs as nrp_std a = nrp_std.UInt64MultiArray() type(a.data) # output is <class 'nrp_core.data.nrp_ros.std_msgs.UInt64MultiArray_data'>
This new class behaves similarly to a Python list
. It supports append
and extend
methods for adding new data. Its elements can accessed by index or iterated and len
will return the number of elements. But other methods of list
type are not supported as index
or sort
. Also attempting to append or extend the object with elements of the wrong type (depending with the array field type) will raise a TypeError
exception.
Another important difference between native Python ROS messages and the NRP-Core Python bindings counterpart is that Python ROS messages allows to initialize the message fields in the object constructor while the NRP-Core Python bindings only have an empty constructor.