π€Practice Day

Table of contents
- π‘ Welcome to the Festival Grounds!
- π§ Recalling What We Know
- π¦ Our Festival Line-Up
- ποΈ Organizing the Workspace
- πΊ Creating DanceBot
- π¦οΈ Rewiring WeatherBot and UmbrellaBot
- π§ͺ Build and Test
- π What Weβve Set Up
- π§ Concept Reinforcement
- πͺ© Let the Dance Begin: Making DanceBot Groove
- π‘ LightBot Joins the Stage
- π§ Rebuild and Source
- π§ͺ Try the Choreography!
- π¬ Letβs Launch the Show
- π Quick Summary
- π οΈ What You Practiced
- π‘ Next Stop: The Big Finale!
- ποΈ Welcome to the Festival Square
- π Festival Output (Sample)
- π Grand Recap
- β¨ Whatβs Next?

π‘ 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
DanceBot
Reconnect
WeatherBot
andUmbrellaBot
using 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
DanceBot
actually dance (publish steps)Connect it with
LightBot
and 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:
DanceBot
announcing dance movesLightBot
flashing lights for each moveUmbrellaBot
reacting 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:
MayorBot
opens the festival with a speechTrafficBot
guides 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. π₯π€π
Subscribe to my newsletter
Read articles from gayatri kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by