
🎡 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 Learned | Role in Today’s Project |
| Packages | Each bot has its own house (code base) |
| Nodes | Every bot has a brain |
| Publishers & Subscribers | Bots talk and listen |
| Messages | Bots speak the same language |
| Launch Files | Town-wide schedule to start everything |
| Logging | Each bot keeps a diary during the event |
| Workspaces | One 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 Name | Role |
MayorBot | Starts the festival (publisher) |
DanceBot | Dances when signaled |
LightBot | Lights up when dancing starts |
UmbrellaBot | Opens umbrella if cloudy |
WeatherBot | Publishes the weather forecast |
Today, we’ll:
Plan the folder structure
Set up a brand new package for
DanceBotReconnect
WeatherBotandUmbrellaBotusing pub-subReview 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
DanceBotactually dance (publish steps)Connect it with
LightBotand othersCreate a launch file for the performance
🧠 Concept Reinforcement
| Concept | Festival Analogy |
| Publisher | Announcer on stage |
| Subscriber | Bots listening from the wings |
| Node | Bot brain executing its act |
| Launch File | Stage Manager calling cues |
| Workspace | Rehearsal 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:
DanceBotannouncing dance movesLightBotflashing lights for each moveUmbrellaBotreacting toWeatherBot'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
| Bot | Function |
| DanceBot | Publishes dance moves |
| LightBot | Reacts to dance moves with lights |
| WeatherBot | Publishes rain/sun info |
| UmbrellaBot | Opens 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:
MayorBotopens the festival with a speechTrafficBotguides crowdsA 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:
| Skill | Bot | Article |
| ROS2 Packages | DoorBot, MayorBot | 1–2 |
| Nodes | ChatterBot | 3 |
| Publishers | WeatherBot | 4 |
| Subscribers | UmbrellaBot | 5 |
| Custom Messages | EmojiBot | 6 |
| Logging | GuardBot | 7 |
| Workspaces | Town Layout | 8 |
| Launch Files | Master Launch | 9 |
| Simulation | Everyone Together | 10 🎉 |
✨ 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. 🥂🤖🎆
Comments
Join the discussionThis post is what would happen if Pixar and ROS2 had a baby. Emotional robots with great system architecture? YES PLEASE.



