Skip to main content

🤖Practice Day

First ROS2 Simulation Day

Published 9 min readMarkdown
Part of seriesROS2
🤖Practice Day

🎡 Welcome to the Festival Grounds!

Robot Town is buzzing. 🏙️ The square is lit up. The bots have all been practicing their routines and today... it’s Performance Day!

Think of this as a robotics parade: each bot has a role — one speaks, one listens, one dances, one makes announcements. But they need coordination. That’s our job!


🧠 Recalling What We Know

Before we begin, let’s quickly look at what we’ve learned so far and how it’ll help today:

What We LearnedRole in Today’s Project
PackagesEach bot has its own house (code base)
NodesEvery bot has a brain
Publishers & SubscribersBots talk and listen
MessagesBots speak the same language
Launch FilesTown-wide schedule to start everything
LoggingEach bot keeps a diary during the event
WorkspacesOne central hub where everything connects

Everything we do in this project will rely on these foundational skills.


📦 Our Festival Line-Up

We’ll have the following bots ready for showtime:

Bot NameRole
MayorBotStarts the festival (publisher)
DanceBotDances when signaled
LightBotLights up when dancing starts
UmbrellaBotOpens umbrella if cloudy
WeatherBotPublishes the weather forecast

Today, we’ll:

  • Plan the folder structure

  • Set up a brand new package for DanceBot

  • Reconnect WeatherBot and UmbrellaBot using pub-sub

  • Review how this connects to earlier bots


🗂️ Organizing the Workspace

We’ll use the same workspace we've been using:

robot_town_ws/
└── src/
    ├── mayor_bot/
    ├── door_bot/
    ├── chatter_bot/
    ├── weather_bot/
    ├── umbrella_bot/
    ├── light_bot/
    ├── traffic_bot/
    ├── town_starter/
    └── dance_bot/         <-- 🕺 Our new star!

Let’s now create dance_bot.


🕺 Creating DanceBot

Open your terminal in the workspace:

cd ~/robot_town_ws/src
ros2 pkg create --build-type ament_python dance_bot

Update the setup.py in dance_bot/:

entry_points={
    'console_scripts': [
        'dance_node = dance_bot.dance_node:main',
    ],
},

Then create the bot's brain file:

cd dance_bot/dance_bot
touch dance_node.py

And edit dance_node.py:

import rclpy
from rclpy.node import Node

class DanceBot(Node):
    def __init__(self):
        super().__init__('dance_bot')
        self.get_logger().info("🕺 DanceBot is warmed up and waiting to groove!")

def main(args=None):
    rclpy.init(args=args)
    node = DanceBot()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

This is a basic node — it doesn’t dance yet, but it’s ready.


🌦️ Rewiring WeatherBot and UmbrellaBot

Now, let's make sure our previous bots are ready for the festival too.

weather_bot/weather_bot/weather_publisher.py (Publishes weather updates)

from std_msgs.msg import String

self.weather_pub = self.create_publisher(String, 'weather', 10)
self.timer = self.create_timer(2.0, self.send_weather)

def send_weather(self):
    forecast = "rainy"  # hardcoded for now
    self.weather_pub.publish(String(data=forecast))
    self.get_logger().info(f"🌧️ Weather today: {forecast}")

umbrella_bot/umbrella_bot/umbrella_listener.py (Subscribes and reacts)

from std_msgs.msg import String

self.subscriber = self.create_subscription(String, 'weather', self.reaction, 10)

def reaction(self, msg):
    if msg.data == "rainy":
        self.get_logger().info("☂️ UmbrellaBot: Rain detected! Opening umbrella.")
    else:
        self.get_logger().info("☂️ UmbrellaBot: All clear.")

🧪 Build and Test

Back in the root of your workspace:

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

Now test the bots individually:

ros2 run weather_bot weather_publisher
ros2 run umbrella_bot umbrella_listener
ros2 run dance_bot dance_node

You should see:

  • WeatherBot reporting rain

  • UmbrellaBot opening its umbrella

  • DanceBot logging its readiness


🎉 What We’ve Set Up

  • A new bot ready to perform

  • Old bots rewired to join the show

  • All bots live in a clean workspace

Next, we’ll:

  • Make DanceBot actually dance (publish steps)

  • Connect it with LightBot and others

  • Create a launch file for the performance


🧠 Concept Reinforcement

ConceptFestival Analogy
PublisherAnnouncer on stage
SubscriberBots listening from the wings
NodeBot brain executing its act
Launch FileStage Manager calling cues
WorkspaceRehearsal space where all bots live

🪩 Let the Dance Begin: Making DanceBot Groove

Right now, DanceBot just logs a message. Let’s give it real dance steps — published in sequence, which other bots can react to!

Step 1: Define the Dance Steps

Update dance_node.py inside dance_bot/dance_bot/:

from std_msgs.msg import String
import random

class DanceBot(Node):
    def __init__(self):
        super().__init__('dance_bot')
        self.publisher_ = self.create_publisher(String, 'dance_moves', 10)
        self.timer = self.create_timer(2.0, self.dance_step)
        self.moves = ["step_left", "step_right", "spin", "jump"]
        self.get_logger().info("🕺 DanceBot is grooving!")

    def dance_step(self):
        move = random.choice(self.moves)
        msg = String()
        msg.data = move
        self.publisher_.publish(msg)
        self.get_logger().info(f"🕺 DanceBot: Performing move '{move}'")

🕺 This bot is now broadcasting dance moves on the dance_moves topic.


💡 LightBot Joins the Stage

Let’s bring in LightBot, who reacts to dance steps and flashes lights for each move!

Create this file: light_bot/light_bot/light_listener.py

from std_msgs.msg import String

class LightBot(Node):
    def __init__(self):
        super().__init__('light_bot')
        self.subscriber = self.create_subscription(String, 'dance_moves', self.react_to_dance, 10)
        self.get_logger().info("💡 LightBot: Ready to sync with DanceBot.")

    def react_to_dance(self, msg):
        self.get_logger().info(f"💡 LightBot: Flashing lights for '{msg.data}' move!")

And update the entry point in light_bot/setup.py:

entry_points={
    'console_scripts': [
        'light_listener = light_bot.light_listener:main',
    ],
},

🔧 Rebuild and Source

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

🧪 Try the Choreography!

In three terminals:

ros2 run dance_bot dance_node
ros2 run light_bot light_listener
ros2 run weather_bot weather_publisher
ros2 run umbrella_bot umbrella_listener

🎉 You’ll see:

  • DanceBot announcing dance moves

  • LightBot flashing lights for each move

  • UmbrellaBot reacting to WeatherBot's forecast

Our town square is ALIVE. 💃


🎬 Let’s Launch the Show

Now we’ll write a launch file to run everything together. We’ll use town_starter as our launch package (already created earlier in Article 9).

Create festival_launch.py inside town_starter/town_starter/:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(package='dance_bot', executable='dance_node', output='screen'),
        Node(package='light_bot', executable='light_listener', output='screen'),
        Node(package='weather_bot', executable='weather_publisher', output='screen'),
        Node(package='umbrella_bot', executable='umbrella_listener', output='screen'),
    ])

Update the entry point in town_starter/setup.py:

entry_points={
    'console_scripts': [
        'festival_launch = town_starter.festival_launch:generate_launch_description',
    ],
},

And update town_starter/launch/festival_launch.py:

mkdir -p town_starter/launch
cp town_starter/town_starter/festival_launch.py town_starter/launch/festival_launch.py

Rebuild:

colcon build
source install/setup.bash

Now launch the entire festival!

ros2 launch town_starter festival_launch.py

🌟 All bots now start together. The town square becomes a stage with lights, announcements, reactions, and dances.


📚 Quick Summary

BotFunction
DanceBotPublishes dance moves
LightBotReacts to dance moves with lights
WeatherBotPublishes rain/sun info
UmbrellaBotOpens umbrella if it's rainy

We’ve connected four bots using pure pub/sub logic and launch orchestration.


🛠️ What You Practiced

  • Custom logic inside publishers & subscribers

  • Coordinated behavior using ROS2 topics

  • Random events and fun choreography

  • Launch files to sync multiple bots

  • Real-world robotics communication patterns


🎡 Next Stop: The Big Finale!

We’re not done yet.

Now, we go BIG:

  • MayorBot opens the festival with a speech

  • TrafficBot guides crowds

  • A new bot joins with music (hint: DJBot)

  • Emoji Mood Updates from each bot

  • And a closing message from the mayor

This will use custom messages, logs, and full launch orchestration.

Grab your tickets. The final performance is about to begin. 🎟️🎤🎶


🏛️ Welcome to the Festival Square

Citizens of Robot Town gather in the town square, ready to perform!
The Mayor takes the stage…


🎙️ 1. MayorBot Announces the Start

Package: mayor_bot
File: announcer.py

from rclpy.node import Node
from std_msgs.msg import String

class MayorBot(Node):
    def __init__(self):
        super().__init__('mayor_bot')
        self.publisher_ = self.create_publisher(String, 'festival_announcement', 10)
        self.timer = self.create_timer(5.0, self.announce)
        self.messages = [
            "📢 Welcome to the Robot Town Festival!",
            "🎉 Let the performances begin!",
            "🤖 Celebrate communication and cooperation!"
        ]
        self.index = 0

    def announce(self):
        if self.index < len(self.messages):
            msg = String()
            msg.data = self.messages[self.index]
            self.publisher_.publish(msg)
            self.get_logger().info(f"MayorBot announces: {msg.data}")
            self.index += 1

🎧 2. DJBot Responds with Music

Package: dj_bot
File: dj_node.py

from rclpy.node import Node
from std_msgs.msg import String

class DJBot(Node):
    def __init__(self):
        super().__init__('dj_bot')
        self.subscription = self.create_subscription(String, 'festival_announcement', self.react, 10)

    def react(self, msg):
        self.get_logger().info(f"🎵 DJBot plays a beat after: '{msg.data}' — 🎶 boom boom BOP!")

🎭 3. EmojiBot Shares Mood Updates

Custom Message (already built in Article 6):

# bot_interfaces/msg/Mood.msg
string bot_name
string mood

Package: emoji_bot
File: emoji_node.py

from bot_interfaces.msg import Mood
from rclpy.node import Node
import random

class EmojiBot(Node):
    def __init__(self):
        super().__init__('emoji_bot')
        self.publisher_ = self.create_publisher(Mood, 'mood_updates', 10)
        self.timer = self.create_timer(3.0, self.send_mood)
        self.moods = ['😎', '🥳', '🤖', '🕺', '🎉']

    def send_mood(self):
        msg = Mood()
        msg.bot_name = 'EmojiBot'
        msg.mood = random.choice(self.moods)
        self.publisher_.publish(msg)
        self.get_logger().info(f"EmojiBot: {msg.bot_name} feels {msg.mood}")

📓 4. MoodListener Records the Town's Vibes

Package: mood_listener
File: mood_listener.py

from bot_interfaces.msg import Mood
from rclpy.node import Node

class MoodListener(Node):
    def __init__(self):
        super().__init__('mood_listener')
        self.subscription = self.create_subscription(Mood, 'mood_updates', self.react, 10)

    def react(self, msg):
        self.get_logger().info(f"📘 MoodListener: {msg.bot_name} is feeling {msg.mood}")

🌄 5. Launch the Festival!

In your town_starter/launch/festival_finale.py:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(package='mayor_bot', executable='announcer', output='screen'),
        Node(package='dj_bot', executable='dj_node', output='screen'),
        Node(package='emoji_bot', executable='emoji_node', output='screen'),
        Node(package='mood_listener', executable='mood_listener', output='screen'),
        Node(package='dance_bot', executable='dance_node', output='screen'),
        Node(package='light_bot', executable='light_listener', output='screen'),
        Node(package='weather_bot', executable='weather_publisher', output='screen'),
        Node(package='umbrella_bot', executable='umbrella_listener', output='screen'),
    ])

Now run the full town festival:

cd ~/robot_town_ws
colcon build
source install/setup.bash
ros2 launch town_starter festival_finale.py

🎆 Festival Output (Sample)

[mayor_bot] 📢 MayorBot announces: Welcome to the Robot Town Festival!
[dj_bot] 🎵 DJBot plays a beat after: 'Welcome to the Robot Town Festival!' — 🎶 boom boom BOP!
[emoji_bot] EmojiBot: EmojiBot feels 🥳
[mood_listener] 📘 MoodListener: EmojiBot is feeling 🥳
[weather_bot] 🌤️ WeatherBot: It's raining ☔
[umbrella_bot] ☂️ UmbrellaBot: Rain detected! Opening umbrella...
[dance_bot] 💃 DanceBot spins!
[light_bot] 💡 LightBot sees: It's raining ☔ → Turning on warm lights
[mayor_bot] 🎉 MayorBot announces: Let the performances begin!
[dj_bot] 🎵 DJBot plays a beat after: 'Let the performances begin!' — 🎶 boom boom BOP!

🏁 Grand Recap

This festival showcased everything we’ve built:

SkillBotArticle
ROS2 PackagesDoorBot, MayorBot1–2
NodesChatterBot3
PublishersWeatherBot4
SubscribersUmbrellaBot5
Custom MessagesEmojiBot6
LoggingGuardBot7
WorkspacesTown Layout8
Launch FilesMaster Launch9
SimulationEveryone Together10 🎉

✨ What’s Next?

Robot Town is thriving. But we’ve only scratched the surface!

In the next set of articles, we’ll explore:

  • 🛠️ Services (Bots asking others to perform tasks)

  • 🔧 Parameters (Bot configuration)

  • 🕹️ Lifecycle nodes (Controlled state machines)

  • 🎛️ RViz2 and simulation tools

  • 🐢 TurtleBot and physical robot control

Stay tuned. The next chapter of Robot Town is just around the corner.
For now… enjoy the afterparty. 🥂🤖🎆

This post is what would happen if Pixar and ROS2 had a baby. Emotional robots with great system architecture? YES PLEASE.

More from this blog