Directory Structure

  • The directory structure of your ROS2 workspace (training_ws) would look like this:
training_ws/
├── build/                   # Colcon build artifacts (build files)
├── install/                 # Colcon install artifacts (setup files)
│   └── local_setup.bash     # Setup script for the workspace
├── log/                     # Logs from the build process
└── src/                     # Source code of ROS packages (contains 'ros_tutorials' here)
    └── ros_tutorials/       # Cloned repository
        ├── turtlesim/       # The turtlesim package
        └── other_packages/  # Other packages inside 'ros_tutorials'
  • build/: Contains the build files generated by colcon build.
  • install/: Contains the installed packages and setup files necessary for running the workspace.
  • log/: Contains logs of the build process for debugging and analysis.
  • src/: The source directory where all ROS2 packages are placed. In this case, it contains the cloned ros_tutorials repository, which includes the turtlesim package.

When you source install/local_setup.bash, it sets up your environment to use the packages in the training_ws workspace.

Create a Package

https://articulatedrobotics.xyz/tutorials/ready-for-ros/packages/

picture 13

ROS2 Python packages

my_package/
├── package.xml    # File containing meta-information about the package
├── resource/
│   └── my_package # Marker file for the package.
├── setup.cfg      # Required when a package has executables, so `ros2 run` can locate them.
├── setup.py       # Contains instructions for how to install the package.
└── my_package/    # A directory with the same name as your package, used by ROS 2 tools to locate your package; it 
                   # contains `__init__.py`.

ROS2 CMake Packages

my_package/  
├── CMakeLists.txt      # Describes how to build the code within the package  
├── include/  
│   └── my_package/     # Directory containing the public headers for the package  
├── package.xml         # File containing meta-information about the package  
└── src/                # Directory containing the source code for the package  
  • Set up workspace
mkdir -p ~/training_ws/src
cd ~/training_ws
  • Create an empty package using CMake
ros2 pkg create --build-type ament_cmake my_package
  • Open the workspace in VS Code
    • Since we’re using python-only code, we can delete the include and src folders which are used for C++ code
cd ..
code .

launch

  • Create a launch folder and add a talker.launch.py file
from launch import LaunchDescription
from launch_ros.actions import Node
 
def generate_launch_description():
    return LaunchDescription({
        Node(
            package='demo_nodes_cpp',
            executable='talker'
        )
    })
  • Add a listener.launch.py file
from launch import LaunchDescription
from launch_ros.actions import Node
 
def generate_launch_description():
    return LaunchDescription([
        Node(
            package='demo_nodes_py',
            executable='listener'
        )
    ])
  • This will launch the talker and listener nodes from the demo_nodes_cpp package:
demo_nodes_cpp/
├── CMakeLists.txt
├── package.xml
├── src/
│   ├── talker.cpp
│   └── listener.cpp
└── launch/
    └── demo_nodes_cpp_launch.py

CMakeLists.txt

  • Update CMakeLists to tell colcon how to build the files
    • Add the following lines just before ament_package()
install(DIRECTORY launch
  DESTINATION share/${PROJECT_NAME}
)

package.xml

  • Update package.xml to include additional information for ROS and colcon to recognize and manage the package, including dependencies (e.g. the demo_nodes_cpp and demo_nodes_py packages)
    • We use <exec_depend> because these dependencies are needed for execution.
    • Alternatively, we could use <build_depend> if the dependencies are required only for building or <depend> for both building and executing.
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>my_package</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="email@gmail.com">Name</maintainer>
  <license>TODO: License declaration</license>
 
  <buildtool_depend>ament_cmake</buildtool_depend>
 
  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>
 
  <exec_depend>demo_nodes_cpp</exec_depend>
  <exec_depend>demo_nodes_py</exec_depend>
 
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>
  • Additionally, it’s good practice to update other fields in the package.xml such as:
    • name: The name of the package.
    • email: The maintainer’s contact email.
    • description: A brief description of the package.
    • license: The license under which the package is distributed.

Build the Package

  • Build the package from the workspace directory
    • This option uses symlinks instead of copies, so you don’t need to rebuild when tweaking certain files
colcon build --symlink-install

Push the package to GitHub

  • Create a repository on GitHub
  • Initialize git (from inside your local my_package directory)
echo "# my_package" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:<github_username>/<repo_name>.git
git push -u origin main

Pull the package onto the Pi

  • Create a robot_ws workspace on the other machine (e.g. Raspberry Pi 4B) and cd into it
    • Make sure SSH authentication is set up
mkdir -p ~/robot_ws/src
cd ~/robot_ws
  • Clone the repo into the src folder
git clone git@github.com:<github_username>/<repo_name>.git
  • cd back into the root of the workspace for both machines and run
colcon build --symlink-install

Test the package

  • cd into the workspace directory and source the workspace (on both machines)
source install/setup.bash

Normally you would have separate terminals for building and running the package

  • Run the publisher node on the dev machine
ros2 launch my_package talker.launch.py
  • Run the publisher node on the pi
ros2 launch my_package listener.launch.py

picture 2