The ROS API and Python
Client Libraries
ROS client libraries allow programs to interact with other ROS processes. There are three primarily supported client libraries:
rclpy
rclpy is a python library that allows a python program to become a ROS 2 node.
import rclpyto use the client library.rclpy.nodedefines theNodeclass- One way to make nodes in ROS 2 is to sub-class
rclpy.node - We focus on this method because it is the most flexible and makes it easier to combine nodes within the same python process.
- It is also possible to instantiate an
rclpy.node.Nodeobject and call it's methods.
- One way to make nodes in ROS 2 is to sub-class
- Each python ROS 2 node has an
entry_pointfunction that is called when the node is started.- The entrypoint function can have any name, and it is registered in the
setup.py. - The
def entry_point_name(args=None)function is passed command line arguments. - Call
rclpy.init(args=args)to have the node parse its ROS command line arguments
- The entrypoint function can have any name, and it is registered in the
- The
Nodeclass has methods that enable- Creating service servers: create_service
- Creating service clients: create_client
- Creating publishers: create_publisher
- Creating subscribers: create_subscription
- Creating timers: create_timer
- Declaring and using parameters: declare_parameters, get_parameter
- The rcl_interfaces package defines some types that are useful for describing and interacting with parameters.
- For example, there are a few basic data types for parameters, outlined in the ParameterType message
- The ParameterDescriptor message allows setting metadata for parameters
- Logging:
- Obtain the logger associated with a node using Node.get_logger
- The Logger API
- There are many other ROS functions and classes available in
rclpy, look at the documentation. - An example of some ROS API functions is available at https://github.com/m-elwin/me495_demo
Interfaces
To use interfaces from a ROS node you must import the corresponding package. This will expose an object that contains the elements in that interface.
# import for a package/msg/MessageType from package.msg import MessageType # import for a package/srv/ServiceType from package.srv import ServiceType # The request type: ServiceType.Request() # The response Type: ServiceType.Response() # Each object has the same field names as set in the IDL file # These types can also be constructed by providing keyword arguments to the constructor # Which in turn contains the field names of the type
- It is also possible to make Custom Interfaces
Naming in ROS
Understanding Names
- Every item in the ROS Computation Graph has a Graph Resource Name
- The link is for ROS 1 as I have not yet found equivalent documentation for ROS 2 and it is substantially similar.
- When using
rclpyfunctions to create nodes, subscribers, clients, and services, each of these entities is provided a name as one of the arguments. - The name is used by
rclpyto register the python object with the appropriate entity in the ROS graph (e.g., publisher/subscriber with a topic). - Names are best thought of as placeholder default values: they can be changed by users when the node runs.
- Every ROS 2 node exists within a =/namespace/
- Namespaces are like directories on Linux: they start from the global namespace (called
/) and can be nested (e.g.,/ns1/ns2/ns3).
- Namespaces are like directories on Linux: they start from the global namespace (called
- Just like paths on Linux, ROS names can be relative or absolute
- An absolute name is any name that starts with a
/ - A relative name is any name that does not start with a
/. This name will be interpreted relative to a context- For example, topics that do not start with a
/become relative to the namespace the node is in.
- For example, topics that do not start with a
- The base name is the name of the entity without any preceding namespaces.
- A
~symbol makes a nameprivate.- The
~gets expanded to the full absolute name of the node (including the base name). - Private is enforced by convention and just means that the node namespace and name are prepended.
- The
- Suppose we have a node called
/this/is/mynode:- The base name of the node is
mynode
- The base name of the node is
- An absolute name is any name that starts with a
- Names should start with a lower case letter, and then can contain letters, or underscores.
Example
Suppose we have a node called /this/is/mynode
- The base name of the node is
mynode. - The namespace of the node is
/this/is. - The
isnamespace is nested under the/thisnamespace
Suppose /this/is/mynode creates a publisher on the hello topic and a subscriber on the /foo/data topic and a service server called ~/help:
- The node (by default) will publish to
/this/is/hello. - The node (by default) will subscribe to
/foo/data. - The node will offer a service (by default) on
/this/is/mynode/help.
Comparison with ROS 1
- In ROS 1, parameters were global and followed the same naming conventions as other entities.
- In ROS 2, parameters are always associated with a specific node and within that node can optionally have their own parameter namespace.
Manipulating Names
- Resources can be remapped to any name that you want using Node Arguments
- This behavior is like a
mvoperation in the Linux filesystem - It enables multiple copies of a node to run with different names for the topics they subscribe to
- Any name referred to in the node (including absolute and private names) can be remapped.
- To remap a specific name use
ros2 run package node --ros-args -r old_name:=new_name- Multiple
-rarguments can be passed after--ros-argsto rename multiple entities
- Multiple
- The node can be renamed using
-r __node:=new_node_namein the above - The namespace can be changed using
-r __ns:=/new_namespace. Thenamespacemust start with a/
- This behavior is like a
- When the node's namespace is changed, all entities (e.g., topics) that used relative names will be moved relative to the provided namespace
- This behavior makes it easy to remap groups of related names
- Namespaces also allow running multiple groups of nodes simultaneously with the same topics
- For example, the
turtlesim_nodesupports multiple turtles, each controlled via the same topics. They do not interfere because each turtle is in its own namespace.
- In practice, ROS nodes should be written with
remappingin mind:- Generally, use simple, base names for ROS nodes, the services they offer, and the topics they publish and subscribe to (so do not include the leading
/.- This way, your node can easily be run under a different namespace without needing to remap each topic individually
- Using absolute node names makes your node less flexible and harder to use.
- Users of the node then remap these topics and services as needed
- Generally, use simple, base names for ROS nodes, the services they offer, and the topics they publish and subscribe to (so do not include the leading
A Node's ROS API
- The publishers, subscribers, services, parameters, and actions a node declares comprise it's ROS API
- They determine how other nodes interact with your node, on a ROS level
- These ROS inter-process communication mechanisms are how you link nodes together, much like how modules, functions, and classes are used from within python.
- These items should be documented in a docstring at the top of the file that defines your node.