Creating Packages and Nodes

In this exercise, we will create our own ROS package and node.

Motivation

The basis of ROS communication is that multiple executables called nodes are running in an environment and communicating with each other in various ways. These nodes exist within a structure called a package. In this module we will create a node inside a newly created package.

Reference Example

Create a Package

Further Information and Resources

Scan-N-Plan Application: Problem Statement

We’ve installed ROS, created a workspace, and even built a few times. Now we want to create our own package and our own node to do what we want to do.

Your goal is to create your first ROS node:

  1. First you need to create a package inside your workspace.
  2. Then you can write your own node

Scan-N-Plan Application: Guidance

Create a Package

  1. cd into the workspace src directory

    • Remember that all packages should be created inside a workspace src directory.
    cd ~/ros2_ws/src
    
  2. Use the ROS command to create a package called myworkcell_core with a dependency on rclcpp

    ros2 pkg create myworkcell_core --dependencies rclcpp
    

    Run ros2 pkg create -h to see more details and options for this command.

    • This command creates a directory and required files for a new ROS package.
    • The first argument is the name of the new ROS package.
    • Use the --dependencies option to specify packages which the newly created package depends on.
  3. There will now be a folder named myworkcell_core. Change into that folder and edit the package.xml file. Edit the file and change the description, author, etc., as desired.

    cd myworkcell_core
    gedit package.xml &
    

    If you forget to add a dependency when creating a package, you can add additional dependencies in the package.xml file.

STOP! We’ll go through a few more lecture slides before continuing this exercise.

Create a Node

  1. In the package folder, create the file src/vision_node.cpp (using gedit).
  • Make sure you know the difference between the workspace src directory and the myworkcell_core package src directory. This node source-file should live at: ~/ros2_ws/src/myworkcell_core/src/vision_node.cpp.
  1. Add the ROS C++ header (include rclcpp.hpp).

    /**
    **  Simple ROS Node
    **/
    #include <rclcpp/rclcpp.hpp>
    
  2. Add a main function (typical in c++ programs). The rest of our code will go inside this function.

    int main(int argc, char* argv[])
    {
    
    }
    
  3. Initialize the ROS CPP middleware interface (must be called once per process).

    // This must be called before anything else ROS-related
    rclcpp::init(argc, argv);
    
  4. Create a ROS node instance.

    auto node = std::make_shared<rclcpp::Node>("vision_node");
    
  5. Print a “Hello World” message using ROS print tools.

    RCLCPP_INFO(node->get_logger(), "Hello, World!");
    
  6. Do not exit the program automatically - keep the node alive.

    // Don't exit the program.
    rclcpp::spin(node);
    

    The complete code should look like this:

    /**
    **  Simple ROS Node
    **/
    #include <rclcpp/rclcpp.hpp>
    
    int main(int argc, char* argv[])
    {
      // This must be called before anything else ROS-related
      rclcpp::init(argc, argv);
    
      // Create a ROS node
      auto node = std::make_shared<rclcpp::Node>("vision_node");
    
      RCLCPP_INFO(node->get_logger(), "Hello, World!");
    
      // Don't exit the program.
      rclcpp::spin(node);
    }
    

    RCLCPP_INFO is one of the many logging methods

    • It will print the message to the terminal output, and send it to the /rosout topic for other nodes to monitor.
    • There are 5 levels of logging: DEBUG, INFO, WARNING, ERROR, & FATAL.
    • To use a different logging level, replace INFO in RCLCPP_INFO or RCLCPP_INFO_STREAM with the appropriate level.
    • Use RCLCPP_INFO for printf-style logging, and RCLCPP_INFO_STREAM for cout-style logging.
  7. Now that you have created the source code for the node, we need to add instructions for building it into an executable program. In the package folder, edit the CMakeLists.txt file using gedit. Define an executable node named vision_node (add_executable), with the source file vision_node.cpp. Also within the CMakeLists.txt, make sure your new vision_node gets linked to the required dependencies.

    add_executable(vision_node src/vision_node.cpp)
    ament_target_dependencies(vision_node rclcpp)
    

    These lines should be place after the section labeled # find dependencies and before the ament_package() call. The flow of a CMakeLists.txt file is almost always to first find all dependencies the current project requires, then to declare the targets the current project is creating, and finally to specify extra information such as how to test the targets and things that projects making use of this one need to know. Note that the term “project” is used here in the context of CMake. Each ROS package acts as a separate CMake project (notice the project(myworkcell_core)) line at the very top of the file).

  • See ament_cmake documentation for more details on common ROS2 CMakeLists rules.
  • You’re allowed to spread most of the CMakeLists rules across multiple lines, which is often required when a target contains many source files or has many dependencies.
  1. We’ve now told CMake about the vision_node executable and how to build it, but to actually run it, the file must be installed along with all the other workspace outputs. Typically, the installation location will be the install/ directory alongside the src/ directory. Add the following lines after ament_target_dependencies but before ament_package into your CMakeLists.txt to declare an installation rule for the vision_node executable:

    # Mark executables for installation
    install(TARGETS vision_node
        DESTINATION lib/${PROJECT_NAME})
    
    • ROS2 installs executables into a package-named subdir in the lib directory.
    • A different set of install rules are needed if your project builds libraries, which are installed in bot the root lib and bin directories.
  2. Build your program (node), by running colcon build in your build terminal window

    • Remember that you must run colcon build from the ros2_ws directory.
    • This will build all of the programs, libraries, etc. in myworkcell_core
    • In this case, it’s just a single ROS node vision_node

Run a Node

  1. Open a terminal to run your node.

    • Remember to run source ~/ros2_ws/install/setup.bash in this new terminal
  2. Run your node.

    ros2 run myworkcell_core vision_node
    

    This runs the program we just created. Remember to use TAB to help speed-up typing and reduce errors.

  3. In a second terminal, check what nodes are running.

    ros2 node list
    

    You should now see a new /vision_node listed.

  4. To stop the node, input Ctrl+C in the terminal where it is running. The node is running as a completely normal executable file so standard Linux process management tools can also stop it (e.g., killall vision_node).

Challenge

Goal: Modify the node so that it prints your name. This will require you to run through the build process again.