Welcome to RoboCity! A Beginner’s Guide to Robotics and ROS2

Welcome to RoboCity! A Beginner’s Guide to Robotics and ROS2

Laying the Blueprint for Your First Robotics Project

Introduction: Building the Blueprint

Imagine a city, vibrant and complex, where every building, road, and public park has a unique purpose, connected by a hidden network that keeps the city functioning. In robotics, ROS2 (Robot Operating System 2) is like the blueprint and infrastructure of this city—linking all parts, orchestrating tasks, and ensuring smooth communication.

In this introductory article, we’re going to start building our city’s blueprint by setting up ROS2 (using ROS2 Humble Hawksbill) and diving into its fundamentals. This will be your foundation for building robots capable of navigating, sensing, and eventually thinking for themselves.

Let’s lay the groundwork for our city’s key structures: a workspace where we organize our projects and nodes that serve as the buildings or landmarks in RoboCity. By the end of this article, you’ll be ready to launch your own mini city!


Setting Up the Foundation

The Role of Robotics
In simple terms, robotics is about creating machines that can perform tasks, often mimicking human capabilities. Whether in factories or our homes, robots rely on intricate software and hardware combinations to execute commands, interact with their environments, and even make decisions.

Where Does ROS2 Fit In?
Just as a city’s infrastructure is essential for connecting different parts, ROS2 acts as the central software framework that allows the various components of a robot to communicate. ROS2 handles everything from basic data exchange to complex commands, serving as the main bridge between hardware and software in robotics.

Analogy: Think of ROS2 as the digital city planner. It coordinates traffic (data), ensures utilities (code functions) are running smoothly, and keeps the infrastructure robust and adaptable as the city (robot system) grows.


ROS2 Concept - Constructing the Blueprint

What is ROS2, and Why Use It?

ROS2 is an upgraded, open-source robotics framework that allows you to create, test, and deploy robots in a flexible environment. The power of ROS2 lies in its modular approach, allowing different components to be built independently yet communicate effectively.

Analogy: Imagine if every building in a city could be designed by different architects but still fit perfectly into the city’s layout. ROS2 ensures each “building” or function works harmoniously, no matter who “constructed” it.


Understanding the Workspace: The City’s Main Hub

Before diving into creating nodes, let’s first understand where they’ll “live.” The ROS2 workspace is like the central hub or planning office of RoboCity, where all the construction plans (project files) are stored and organized.

  1. What is a ROS2 Workspace?

    • In ROS2, the workspace is essentially a directory on your computer where all the code, nodes, and packages related to your project will be organized.

    • The workspace allows for easy management, reuse, and deployment of components, making it ideal for complex projects.

  2. Creating Your ROS2 Workspace

    • To start building RoboCity, we’ll set up our workspace. Let’s walk through the setup step-by-step.

Step-by-Step Guide: Setting Up Your ROS2 Workspace

Flowchart: Workspace Setup Process

Start --> Open Terminal --> Create Workspace Directory --> Navigate to Directory --> Initialize Workspace with colcon --> Workspace Ready!
  1. Open Your Terminal
    ROS2 uses the command line interface to execute commands, so start by opening your terminal. (If you’re on Windows, I recommend using the Windows Subsystem for Linux or a virtual machine with Linux installed.)

  2. Create the Workspace Directory
    Think of this directory as the main planning office for our city.

     mkdir -p ~/robocity_ws/src
    
    • mkdir -p is the command to create a directory.

    • ~/robocity_ws/src specifies the workspace and source folder.

  3. Navigate to the Workspace

     cd ~/robocity_ws
    
  4. Initialize the Workspace
    ROS2 needs some setup files to understand this workspace. We’ll use the colcon tool for this, which helps build and manage the workspace.

     colcon build
    

    This command will compile the workspace and generate the necessary files for ROS2.

Tip: Each time you modify files or add new nodes to the workspace, remember to run colcon build to compile these changes.


Introduction to Nodes - Building the Landmarks in RoboCity

Now that our workspace (planning office) is ready, it’s time to build some structures! Nodes in ROS2 are like the buildings or landmarks of RoboCity, each with a unique function. Some nodes may “talk” to others by sending data (messages), while others “listen” to instructions or commands.

What is a Node?

A node is essentially a program that performs a specific function in the robot’s system. In a robot’s city, nodes can represent:

  • Sensors collecting data (like security cameras in a city),

  • Actuators moving parts (like a traffic signal),

  • Controllers orchestrating tasks (like a traffic control center).

Each node operates independently, meaning you can create and test them individually without affecting other parts of the city.

Analogy: Imagine each node as a small shop, office, or utility building in RoboCity, all connected by the same infrastructure. Just like a city, you can expand or upgrade nodes as needed!


Project 1: “City Blueprint Simulation”

Objective:

Create a simple city with nodes representing different city sectors, like a park, office, and house. Each node will function independently, simulating the modular nature of ROS2.

Setting Up the Project

Flowchart: Project Setup and Execution

Setup Workspace --> Create Node Directories --> Write Node Code --> Build Workspace --> Execute Nodes
File Structure

Here’s how to organize your files in the workspace for this project:

robocity_ws/
└── src/
    ├── park_node/
    ├── office_node/
    └── house_node/
Creating the Nodes
  1. Navigate to the src Folder

     cd ~/robocity_ws/src
    
  2. Create Directories for Each Node
    These directories represent different sectors of the city.

     mkdir park_node office_node house_node
    
  3. Create the Node Files
    Each node will be a simple Python script that simulates activity in its sector.

    • Navigate into each folder and create a file named node.py:

        cd park_node
        touch node.py
      

Node Code: Simulating City Sectors

Here’s an example code for park_node/node.py to represent the park:

# park_node/node.py

# Importing the rclpy library, which is essential for working with ROS2 in Python.
import rclpy
# Importing the Node class from rclpy.node. This Node class provides the basic framework
# for creating nodes, allowing us to use ROS2 functions like logging, publishers, and subscribers.
from rclpy.node import Node

# Define a class 'ParkNode' that inherits from 'Node'. Think of this as creating a "building blueprint" 
# in our robotic city (RoboCity) where each node represents a specific landmark or function.
class ParkNode(Node):
    def __init__(self):
        # Initialize the node with the name 'park_node'.
        # 'super().__init__('park_node')' tells ROS2 to register this node with the name 'park_node'.
        # This is like giving our "park building" an official name within the city.
        super().__init__('park_node')

        # Use the node's logger to display a welcome message in the console.
        # This acts as a virtual "sign" outside the park, letting anyone know it's open and ready.
        self.get_logger().info('Welcome to the Park! Trees and benches await you.')

# Define the main function, which initializes and runs our node.
# This is like turning on the power to bring our park to life within RoboCity.
def main(args=None):
    # Initialize ROS2, setting up the necessary framework for the node to operate.
    rclpy.init(args=args)

    # Create an instance of 'ParkNode' named 'park_node'.
    # This is like constructing our park using the blueprint we created in the class definition.
    park_node = ParkNode()

    # Keep the node active and responsive, allowing it to continue running.
    # 'rclpy.spin()' is like keeping the park open and accessible, with the node constantly active.
    rclpy.spin(park_node)

    # When the node is done, clean it up properly.
    # Destroy the node, which is like closing and removing all resources of the park.
    park_node.destroy_node()

    # Shut down the ROS2 system for this node, ending all processes cleanly.
    rclpy.shutdown()

# Standard Python practice to check if this script is being run directly.
# If it is, it will call the main function to execute the code.
if __name__ == '__main__':
    main()

This code introduces a simple ROS2 node that simulates a park. When you run the node, it displays a message, “Welcome to the Park! Trees and benches await you.”

Explanation: Park Setup in RoboCity

  1. Creating the Blueprint (Class Definition)
    The ParkNode class is like creating a blueprint for a new park in RoboCity. This blueprint outlines what the park will be called (park_node) and defines the message displayed when the park opens (a greeting message). By naming the node "park_node", we ensure it has a unique identity within the city.

  2. Constructing the Park (Instantiating the Node in main)
    In the main function, we initialize ROS2 with rclpy.init(), which is like powering up the city. We then create the actual park building by making an instance of ParkNode, represented by the variable park_node. This step takes our blueprint and constructs the physical "park" in RoboCity.

  3. Opening the Park (Spinning the Node)
    By calling rclpy.spin(park_node), we "open the park" to the city, allowing it to stay active. The node will keep running, and the message "Welcome to the Park! Trees and benches await you." will be displayed to signal that the park is accessible.

  4. Closing the Park (Cleanup)
    When the park is no longer needed, we close it by calling park_node.destroy_node() to free up resources. Finally, rclpy.shutdown() completely powers down ROS2 for this node, ensuring a clean exit from RoboCity.


Step-by-Step Code Explanation

  1. Imports

    • rclpy and Node are essential ROS2 components. rclpy provides the ROS2 tools, while Node gives us a framework to define a functional ROS2 node.
  2. Class Definition: ParkNode

    • The ParkNode class, which inherits from Node, is initialized with the name 'park_node'.

    • The get_logger().info() function logs a message when the node starts, acting as a greeting from the park.

  3. The main() Function

    • rclpy.init(): Initializes ROS2, making it ready for nodes to be created and activated.

    • park_node = ParkNode(): Creates an instance of the ParkNode class, making our park "building" operational.

    • rclpy.spin(park_node): Keeps the node active, so it’s ready for interactions or further processes.

    • park_node.destroy_node(): Cleans up the node resources when it’s no longer needed.

    • rclpy.shutdown(): Shuts down the ROS2 process for this node, ending its activity.

Explanation: Each node is like a different building in the city, with the ParkNode simulating the park’s activities. The get_logger().info() line outputs messages, which you’ll see in the terminal.


Expanding the City

With our RoboCity blueprint established and initial landmarks (nodes) in place, it’s time to expand! So far, each “building” or node has functioned independently, but a true city thrives on connection and communication. Now, we’ll register our nodes and establish a communication network across RoboCity, making the nodes aware of each other in a structured environment.

To do this, we’ll introduce namespaces to help organize the nodes within ROS2 and create a setup where each node has a unique identity, allowing it to communicate seamlessly within our city.


Nodes as City Structures - Introducing Namespaces

In ROS2, namespaces allow us to organize nodes so they’re easy to manage and don’t overlap in functionality. Imagine namespaces as the districts of RoboCity, where each node (building) has a unique address, making it easy to locate and interact with.

What is a Namespace?

A namespace in ROS2 works like an address prefix, grouping nodes logically so they don’t interfere with one another. For example, imagine a namespace as a specific street in our city, and each node on that street has a unique building number.

Analogy: Think of namespaces as neighborhoods in a city. Just as two houses can have the same number if they’re on different streets, two nodes can share a name as long as they’re in separate namespaces.


Project 2 - “Robot Registration”

Our goal is to expand RoboCity by assigning unique addresses to each node and simulating a simple registration process where nodes check in and register their location in the city using namespaces.

Objective

In this project, each node will “register” itself as a unique part of the city, with its own address in a specific namespace. This will introduce the concept of namespaces, allowing us to organize the nodes systematically and ensuring smooth communication.


File Structure: Organizing Nodes by Namespaces

Let’s expand our robocity_ws workspace to group nodes in namespaces. The structure should look like this:

robocity_ws/
└── src/
    ├── park/
    │   └── park_node.py
    ├── office/
    │   └── office_node.py
    └── house/
        └── house_node.py

Each directory (e.g., park/, office/) represents a unique namespace for a specific sector of the city.

Flowchart: Node Creation and Registration Process

Create Workspace --> Create Namespaced Node Directories --> Add Code for Registration --> Build and Run --> Nodes Registered in Namespaces

Step 1: Creating the Namespaced Nodes

  1. Navigate to the src Folder

     cd ~/robocity_ws/src
    
  2. Create Directories Representing Namespaces

     mkdir park office house
    
  3. Add Node Files for Each Namespace
    Each directory contains a unique node.py file that registers itself when launched. Navigate into each folder and create a node.py file as follows:

     cd park
     touch node.py
    

Step 2: Coding the Namespaced Nodes

Code Example: Registering the Park Node

Let’s create the park_node.py code. This node will register itself as part of the “park” namespace and log a custom welcome message.

# park/park_node.py

import rclpy  # Import the ROS2 Python client library
from rclpy.node import Node  # Import the Node class for ROS2 nodes

# Define a ParkNode class inheriting from Node
class ParkNode(Node):
    def __init__(self):
        # Initialize the node with the name 'park_node' in the 'park' namespace
        super().__init__('park_node', namespace='park')

        # Log a message indicating this node is active in the 'park' namespace
        self.get_logger().info('Park Node Registered in the Park Namespace!')

# Define the main function to initialize and run the node
def main(args=None):
    rclpy.init(args=args)  # Initialize ROS2
    park_node = ParkNode()  # Create an instance of ParkNode
    rclpy.spin(park_node)  # Keep the node running and active
    park_node.destroy_node()  # Clean up the node after shutdown
    rclpy.shutdown()  # Shut down ROS2 for this node

# Run the main function if this script is executed directly
if __name__ == '__main__':
    main()

This code creates a node that registers itself within the park namespace and logs a message confirming its location in RoboCity.

Explanation

  • Node Class: The ParkNode class inherits from the Node class, initializing the node in the “park” namespace.

  • Logger: When initialized, the get_logger().info() method outputs the message “Park Node Registered in the Park Namespace!” simulating a simple registration.

  • In super().__init__('park_node', namespace='park'), we specified namespace='park'. This registers park_node under the park namespace within ROS2 each time it runs.

  • The node name is still park_node, but now it exists within the park namespace, making it accessible under /park/park_node.


Code Example: Registering the Office Node

The code for the office node is similar, but logs a unique message for its namespace.

# office/office_node.py

# Import the ROS2 Python client library to access ROS2 functionality
import rclpy
# Import the Node class from ROS2, which provides the framework for creating a node
from rclpy.node import Node

# Define a class OfficeNode that inherits from Node, representing a unique node in the system
class OfficeNode(Node):
    def __init__(self):
        # Initialize the node with the name 'office_node'
        super().__init__('office_node')

        # Log a message to indicate that the node is active in the 'office' namespace
        self.get_logger().info('Office Node Registered in the Office Namespace!')

# Define the main function to initialize and run the OfficeNode
def main(args=None):
    # Initialize ROS2, setting up the framework for nodes to operate
    rclpy.init(args=args)

    # Create an instance of OfficeNode
    office_node = OfficeNode()

    # Keep the node active, allowing it to run continuously
    rclpy.spin(office_node)

    # Once the node is shut down, destroy the node to free resources
    office_node.destroy_node()

    # Shut down ROS2 for this specific node
    rclpy.shutdown()

# Standard Python practice to check if this script is executed directly
# If true, it will run the main function to execute the node
if __name__ == '__main__':
    main()

Step 3: Building and Running the Nodes in Namespaces

Now that our nodes are coded, let’s build and run them.

  1. Navigate to the Workspace Root

     cd ~/robocity_ws
    
  2. Build the Workspace

     colcon build
    
  3. Source the Setup File
    This allows ROS2 to recognize the workspace files.

     source install/setup.bash
    
  4. Launch Each Node Individually with Namespaces

    Launch the nodes with their specific namespaces using the --ros-args --namespace option:

     ros2 run park park_node
     ros2 run office office_node --ros-args --namespace office
     ros2 run house house_node --ros-args --namespace house
    

Step 4: Verifying the Namespace

To confirm the node is running in their respective namespace, you can use the following command to list active nodes:

ros2 node list

You should see the node listed as:

/park/park_node
/office/office_node
/house/house_node

Project Summary and Flowchart: “Robot Registration”

This flowchart shows the Robot Registration Process across namespaces.

Initialize Workspace --> Write Node Code in Namespaces --> Build and Source --> Launch Nodes with Namespaces --> Nodes Registered and Logging Messages

By organizing each node in a unique namespace, we’ve created a more structured city where every “building” knows its address. This setup will make it easier for nodes to interact with each other as RoboCity grows.


Wrap-Up and Conclusion

In this part, we expanded RoboCity by introducing the concept of namespaces, which act as districts within the city. By grouping each node under a specific namespace, we’ve ensured that RoboCity has a clear and organized structure, setting up each node as a unique part of the city.

As we progress, we’ll begin connecting these nodes so they can “talk” to each other, creating an interconnected city ready for more complex tasks and collaborative behaviors.


Deepening Our City’s Connections

In the next article, we’ll dive deeper into ROS2 nodes by introducing publishers and subscribers, the foundation of data exchange in ROS2. Get ready to make RoboCity a bustling, connected network!