You probably know what ROS2 nodes are. But if doesn’t, ROS2 nodes are the basic building blocks of a ROS2 system. They are independent processes that communicate with each other through topics, services, and actions. But you don’t need separate folders for each node. One of the mistake I did when I started with ROS2. I created a separate folder for each node. But you can have multiple nodes in a package.
A package is an organizational unit that contains your ROS 2 code, while a node is an executable process that performs computation. In ROS 2, nodes are organized into packages, meaning you must create a package before you can create a node.
Understanding the Core Concepts
Packages
Packages are the fundamental units for organizing, building, and distributing ROS 2 code. They allow you to release your work so others can build and use it easily. A single workspace can contain multiple packages, each in their own folder, and packages can use different build types (CMake for C++, Python, or mixed). roboticsunveiled
Nodes
Nodes are executable processes that perform specific computational tasks. Multiple nodes within packages communicate with each other through topics, services, actions, and parameters. Each node should have a single, well-defined purpose in your robot application. docs.ros
Creating ROS 2 Packages
Prerequisites
Before creating packages, ensure you have ROS 2 installed, your environment sourced, and a workspace created. Navigate to the src directory of your workspace before running package creation commands. roboticsbackend
Python Package Creation
To create a Python package, use:
cd ~/ros2_ws/src/
ros2 pkg create --build-type ament_python my_python_pkg
You can also add a node during creation:
ros2 pkg create --build-type ament_python --node-name my_node my_package
C++ Package Creation
For C++ packages:
cd ~/ros2_ws/src/
ros2 pkg create --build-type ament_cmake my_cpp_pkg
With a node:
ros2 pkg create --build-type ament_cmake --node-name my_node my_package
Adding Dependencies
Specify dependencies during creation:
ros2 pkg create --build-type ament_python my_package --dependencies rclpy std_msgs
Python Package File Structure
Complete Directory Layout
my_python_pkg/
├── my_python_pkg/
│ ├── __init__.py
│ └── my_python_node.py
├── resource/
│ └── my_python_pkg
├── test/
│ ├── test_copyright.py
│ ├── test_flake8.py
│ └── test_pep257.py
├── package.xml
├── setup.py
└── setup.cfg
Key Files Explained
package.xml: Contains metadata and dependencies for the package. You must edit the description, maintainer, and license fields before publishing: docs.ros
<?xml version="1.0"?>
<package format="3">
<name>my_python_pkg</name>
<version>0.0.0</version>
<description>Your package description</description>
<maintainer email="your@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
<buildtool_depend>ament_python</buildtool_depend>
<depend>rclpy</depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
setup.py: The Python equivalent of CMakeLists.txt, defining what to install and how to link dependencies. This file contains entry points that make your nodes executable: roboticsbackend
from setuptools import setup
package_name = 'my_python_pkg'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='Your Name',
maintainer_email='your@email.com',
description='Package description',
license='Apache License 2.0',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'node_name = my_python_pkg.my_python_node:main'
],
},
)
setup.cfg: Specifies where scripts will be installed. No modifications needed for basic usage. docs.ros
my_python_pkg/ folder: Contains all your Python nodes. The folder name must match your package name. docs.ros
resource/ folder: Required for ROS 2 to find your package. roboticsbackend
C++ Package File Structure
Complete Directory Layout
my_cpp_pkg/
├── include/
│ └── my_cpp_pkg/
├── src/
│ └── my_node.cpp
├── CMakeLists.txt
└── package.xml
Key Files Explained
CMakeLists.txt: Defines how the package is built and linked. Essential components include: ros-learnings.hashnode
cmake_minimum_required(VERSION 3.5)
project(my_cpp_pkg)
# Find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
# Add executable
add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp)
# Install targets
install(TARGETS
my_node
DESTINATION lib/${PROJECT_NAME})
ament_package()
include/ folder: Contains public headers for your package. docs.ros
src/ folder: Contains C++ source code files. docs.ros
Creating Nodes Within Packages
Python Node Example
Create a node file in the package directory:
cd ~/ros2_ws/src/my_python_pkg/my_python_pkg/
touch my_python_node.py
Basic node structure:
import rclpy
from rclpy.node import Node
class MyPythonNode(Node):
def __init__(self):
super().__init__("my_node_name")
self.get_logger().info("Node has been created")
def main(args=None):
rclpy.init(args=args)
node = MyPythonNode()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == "__main__":
main()
Add the entry point to setup.py:
entry_points={
'console_scripts': [
'test = my_python_pkg.my_python_node:main'
],
},
Add dependencies to package.xml:
<depend>rclpy</depend>
C++ Node Example
The --node-name argument automatically creates a basic C++ node in the src/ directory. Nodes inherit from the rclcpp::Node class. docs.ros
Building and Running
Compile Your Package
From the workspace root:
cd ~/ros2_ws
colcon build --packages-select my_package
Compiling is necessary even for Python to install scripts where they can be found by ros2 run, pass parameters, and work with launch files. roboticsbackend
Source the Workspace
Open a new terminal and source:
source ~/ros2_ws/install/setup.bash
Run a Node
ros2 run my_package node_name
Adding Additional Files
Launch Files
Create a launch/ folder at the package root and modify setup.py:
import os
from glob import glob
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'),
glob('launch/*.launch.py')),
],
Configuration Files
Create a config/ folder for YAML files and add to setup.py:
(os.path.join('share', package_name, 'config'),
glob('config/*.yaml')),
Package Organization Best Practices
Naming Conventions
- Use lowercase with underscores (e.g.,
my_robot_navigation) automaticaddison - Add robot-specific prefix:
my_robot_for robot-specific functionality automaticaddison - Use descriptive suffixes indicating purpose automaticaddison
Structural Guidelines
- One package should have one independent purpose roboticsbackend
- Each package should be replaceable without breaking other packages roboticsbackend
- Use minimum necessary dependencies roboticsbackend
- Avoid circular dependencies (A depends on B, B depends on A) roboticsbackend
- Create separate
my_robot_msgspackage for all message/service/action definitions roboticsbackend - Use
my_robot_descriptionpackage for URDF/meshes roboticsbackend - Keep launch files in a dedicated bringup package roboticsbackend
Mixed C++ and Python Packages
For packages with both languages, use ament_cmake build type and add ament_cmake_python as a buildtool dependency in package.xml. This allows configuring Python setup through CMake. roboticsbackend
Key Differences Summary
| Aspect | Package | Node |
|---|---|---|
| Definition | Organizational unit for code | Executable process performing computation |
| Contains | One or more nodes, config files, launch files | Single executable with specific purpose |
| Created with | ros2 pkg create command | Python/C++ code within package |
| Build system | ament_cmake or ament_python | Compiled/installed as part of package |
| Purpose | Organize and distribute code | Perform specific computational tasks |
Understanding this hierarchy - packages contain nodes - is fundamental to ROS 2 development. Proper organization ensures scalable, maintainable robot applications. husarion