๐Ÿ Letโ€™s Build Our First Robot Home

gayatri kumargayatri kumar
8 min read

๐Ÿ™๏ธ Welcome to the Construction Site

In Robot Town, every robot lives in its own home, and that home is a ROS 2 package.

Think of it like this:

๐Ÿ˜๏ธ Robot Town
โ”œโ”€โ”€ MayorBot (Package)
โ”‚   โ”œโ”€โ”€ Kitchen (Python Scripts)
โ”‚   โ”œโ”€โ”€ Address Plate (setup.py)
โ”‚   โ”œโ”€โ”€ Blueprints (package.xml)
โ”‚   โ””โ”€โ”€ Front Door (Entry Point)

This article will walk you through building one such home โ€” DoorBotโ€™s house. It will respond when called, like a voice-controlled door.


๐Ÿงฑ Step 1: Navigate to the Town Plot (Your Workspace)

Head to your workspaceโ€™s src directory:

cd ~/robot_town_ws/src

This is where all the robot homes (packages) live.


๐Ÿงฐ Step 2: Letโ€™s Lay the Foundation โ€” Create the Package

Weโ€™ll use the ros2 pkg create tool to generate our new home for DoorBot.

ros2 pkg create --build-type ament_python door_bot

What this command does:

  • Creates a folder named door_bot

  • Sets it up for Python-based code (ament_python is the build system)

  • Adds essential files like setup.py and package.xml


๐Ÿ—๏ธ Folder Structure Breakdown

Hereโ€™s what we get:

door_bot/
โ”œโ”€โ”€ door_bot/         โ† Actual code lives here (like the robot's rooms)
โ”‚   โ””โ”€โ”€ __init__.py
โ”œโ”€โ”€ package.xml       โ† Identity card: describes the robot and its dependencies
โ”œโ”€โ”€ setup.cfg         โ† Wiring instructions for installing
โ”œโ”€โ”€ setup.py          โ† The robotโ€™s front door: used to launch it
โ””โ”€โ”€ resource/
    โ””โ”€โ”€ door_bot      โ† Used internally to register your package

โš ๏ธ Wait, why is there a door_bot inside door_bot?
The outer folder is the house, and the inner folder contains the rooms (Python files).
ROS 2 expects your code inside this second-level directory.


๐Ÿšช Step 3: Add a Script โ€” Make the DoorBot Alive

Navigate to the code folder:

cd door_bot/door_bot

Create a file named door.py:

touch door.py

Paste this simple code in:

# Import the core ROS2 Python interface
import rclpy

# Import the base class used to create ROS2 nodes
from rclpy.node import Node

# ๐Ÿšช DoorBot is a friendly gatekeeper in Robot Town!
# This node just starts up and announces it's ready.
class DoorBot(Node):
    def __init__(self):
        # Initialize the node with the name 'door_bot'
        super().__init__('door_bot')

        # Log a message to show that the DoorBot is active
        self.get_logger().info("๐Ÿšช DoorBot: Ready at your service!")

# ๐Ÿ Main function โ€“ the entrance point for this ROS2 program
def main(args=None):
    # Initialize the ROS2 Python client library
    rclpy.init(args=args)

    # Create an instance of our DoorBot node
    node = DoorBot()

    # Keep the node running so it can continue to operate
    rclpy.spin(node)

    # Clean up the node when shutting down
    node.destroy_node()

    # Shut down the ROS2 client library
    rclpy.shutdown()

๐Ÿง  Whatโ€™s Going On Here?

LineMeaning
import rclpyROS 2 Python client library
NodeBase class for all bots in ROS 2
self.get_logger().info(...)Print messages in ROS-style
rclpy.spin(node)Keeps the bot running until stopped

This is a minimal living bot. It doesnโ€™t do much โ€” just wakes up and announces itself.


๐Ÿ› ๏ธ Step 4: Update setup.py with Entry Point

Entry points = main switches to activate your bots.

Edit setup.py:

entry_points={
    'console_scripts': [
        # ๐Ÿ—๏ธ Create a terminal command named 'door'
        # When you run `ros2 run door_bot door`, it executes the `main()` function
        # from the `door.py` file inside the `door_bot` package.
        'door = door_bot.door:main',
    ],
},

This tells ROS 2:

โ€œWhen someone runs ros2 run door_bot door, go to door.py and run main().โ€


๐Ÿงฝ Step 5: Clean Workspace & Build

Go back to the root of your workspace:

cd ~/robot_town_ws
colcon build

After building, source the environment:

source install/setup.bash

๐Ÿง  Wait, what is colcon build doing?

Itโ€™s like a contractor assembling the robot house:

  • Collects all packages in src

  • Installs them in install/

  • Generates necessary files (including the entry_points!)

๐Ÿ“Œ Why source install/setup.bash?

This โ€œconnects the power gridโ€ โ€” it tells your terminal:

โ€œHereโ€™s where the new bots live. You can now run them.โ€


๐Ÿ”‘ What Youโ€™ve Built So Far

  • A real ROS 2 package named door_bot

  • With a basic executable script

  • That runs like this:

ros2 run door_bot door

Youโ€™ll see:

[INFO] [door_bot]: ๐Ÿšช DoorBot: Ready at your service!

๐Ÿ“ฆ Recap of Where We Are

So far, you've:

  • Created a ROS 2 package named door_bot

  • Added a Python script with a basic bot (DoorBot)

  • Understood how colcon build and setup.bash work

  • Launched your bot using ros2 run

Now, weโ€™ll decorate the home, make the bot do something real, and understand how this house fits in the larger neighborhood (aka: multiple packages in a workspace).


๐Ÿ” Letโ€™s Add a Function to the DoorBot

Just logging a message is coolโ€ฆ but letโ€™s go a step further.
Letโ€™s make DoorBot respond to a knock.

๐Ÿšช Update door.py like this:

# Import the core ROS2 Python client library
import rclpy

# Import the base Node class so we can create our own node
from rclpy.node import Node

# ๐Ÿšช DoorBot is now more than just polite โ€“ it opens the door on a schedule!
class DoorBot(Node):
    def __init__(self):
        # Initialize the node with the name 'door_bot'
        super().__init__('door_bot')

        # Let the town know DoorBot is up and running
        self.get_logger().info("๐Ÿšช DoorBot: Ready at your service!")

        # ๐Ÿ•’ Create a timer that calls the open_door method every 5 seconds
        self.timer = self.create_timer(5.0, self.open_door)

    # ๐Ÿšช This function simulates the door opening โ€“ it gets called by the timer
    def open_door(self):
        self.get_logger().info("๐Ÿšช DoorBot: The door opens... creaaak!")

# ๐Ÿ This is the starting point of the program
def main(args=None):
    # Initialize the ROS2 Python communication system
    rclpy.init(args=args)

    # Create an instance of DoorBot
    node = DoorBot()

    # Keep DoorBot alive and responding
    rclpy.spin(node)

    # Cleanup when shutting down
    node.destroy_node()
    rclpy.shutdown()

๐Ÿง  Whatโ€™s Happening Now?

LinePurpose
self.create_timer(5.0, self.open_door)Run open_door() every 5 seconds
open_door()Custom function that simulates door opening

Now your bot is alive and responsive โ€” it's performing actions on its own. This is a basic intro to ROS 2's timer system (like scheduled jobs inside your bot).


๐Ÿ“Š Flowchart: Life of a ROS 2 Node in a Package

t+---------------------+
| colcon build        |
+---------------------+
         โ†“
+---------------------+
| install/setup.bash  |
+---------------------+
         โ†“
+---------------------+
| ros2 run door_bot door  |
+---------------------+
         โ†“
+---------------------+
| 1. rclpy.init()          |
| 2. Node created          |
| 3. Timer starts          |
| 4. Callback runs every X |
+---------------------+

๐Ÿก When You Have Multiple Robot Homes

Letโ€™s say DoorBot gets neighbors: light_bot, cleaner_bot, etc.

Your workspace will look like this:

robot_town_ws/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ door_bot/
โ”‚   โ”œโ”€โ”€ light_bot/
โ”‚   โ””โ”€โ”€ cleaner_bot/
โ”œโ”€โ”€ build/
โ”œโ”€โ”€ install/
โ””โ”€โ”€ log/

Each package (house) goes into src/.

Then:

cd ~/robot_town_ws
colcon build
source install/setup.bash

All bots will be built together and powered on via sourcing.
Now, running any of them is as easy as:

ros2 run light_bot sparkle
ros2 run cleaner_bot sweep

๐Ÿ’ก Tip: Always cd into the root of your workspace before building.


๐Ÿงณ What Goes Inside a Package?

File/FolderRole
package.xmlMetadata, like the robotโ€™s name and dependencies
setup.pyThe robot's launcher file (entry points)
setup.cfgAdditional setup info
resource/Internal ID marker
<package>/<script>.pyYour actual botโ€™s brain ๐Ÿง 

๐Ÿง  When Would You Use Multiple Workspaces?

Sometimes, your robot grows too big. You may want:

  • Separate workspaces for different teams (navigation, sensors)

  • An overlay workspace to test new features without breaking stable code

In those cases:

mkdir -p ~/nav_ws/src
mkdir -p ~/vision_ws/src

Each workspace is built and sourced independently.


๐Ÿงช Mini Project: Build a Smarter DoorBot

๐ŸŽฏ Goal: Add a feature that lets DoorBot greet the user by name.

Add this to __init__:

# ๐Ÿ“ Declare a parameter called 'guest_name' with a default value of 'friend'
# This allows us to customize who DoorBot greets using launch files or CLI!
self.declare_parameter('guest_name', 'friend')

Update open_door():

def open_door(self):
    # ๐Ÿ—๏ธ Retrieve the current value of the 'guest_name' parameter
    name = self.get_parameter('guest_name').get_parameter_value().string_value

    # ๐Ÿค— Greet the guest by name when the door opens
    self.get_logger().info(f"๐Ÿšช DoorBot: Welcome in, {name}!")

How the parameter retrieval is working broken down:

def open_door(self):
    # ๐Ÿ” First, get the parameter object named 'guest_name' from the node's parameter server
    param = self.get_parameter('guest_name')
    # The parameter object contains the value wrapped in a ParameterValue message

    # ๐Ÿ“ฆ Extract the actual value from the parameter object
    # get_parameter_value() returns a ParameterValue object, which can hold different types
    param_value = param.get_parameter_value()

    # ๐ŸŽฏ Since we expect a string parameter, access the string_value attribute to get the plain string
    name = param_value.string_value

    # ๐Ÿ“ Now, use the node's logger to print out an informational message
    # get_logger() returns the node's logging interface which manages output formatting and verbosity
    logger = self.get_logger()

    # โ„น๏ธ info() is a method of the logger used for informational-level logs
    # It prints the message to the console (or wherever the ROS2 logging is configured to send output)
    logger.info(f"๐Ÿšช DoorBot: Welcome in, {name}!")

Now run like this:

ros2 run door_bot door --ros-args -p guest_name:=Alice

๐Ÿ“ฆ Congrats โ€” you've now:

  • Declared a ROS 2 parameter

  • Passed it from the command line

  • Customized your botโ€™s behavior


โœ… What You Learned in This Article

  • What a ROS 2 package is and how to create one

  • Folder structure explained like a real-world house

  • Wrote a Python node with a timer

  • Built with colcon, launched with ros2 run

  • Understood multiple packages in a single workspace

  • Declared and used parameters in ROS 2


๐Ÿš€ Up Next: Talking Bots!

๐Ÿ‘‹ The next stop in Robot Town is all about Nodes โ€” your bots' walkie-talkies.
Weโ€™ll build a ChatterBot that gossips every second and eventually introduce two bots that talk to each other across houses.

10
Subscribe to my newsletter

Read articles from gayatri kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

gayatri kumar
gayatri kumar