Skip to main content

Command Palette

Search for a command to run...

๐Ÿค–Practice Day

First ROS2 Simulation Day

Published
โ€ข9 min readโ€ขView as Markdown
๐Ÿค–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. ๐Ÿฅ‚๐Ÿค–๐ŸŽ†

S

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

GeeKee's Odyssey

113 posts