MAE41115 | Module 4 ROS 2 From Concepts to Production
Module 4
Robot Operating System 2 (ROS 2) From Concepts to Production Robotics
Detailed Teaching Notes with Step-by-Step Worked Examples
Course: MAE41115 Industrial Data Communication and Processing
Instructor: Dr. Golak Bihari Mahanta
Department of Mechatronics and Automation Engineering
National Institute of Technology Patna
How to Read These Notes
This module is a thorough rst course in ROS 2 , the modern open-source software framework
that powers most professional robotics today from research labs to autonomous warehouses
to inspection robots like ours.
You will leave the module with three things:
1. A mental model of how ROS 2 organises a robot's software (nodes, topics, services,
actions, lifecycle, composition).
2. Working knowledge of the tooling (colcon, rclpy, launch les, RViz2, ros2bag).
3. The ability to read and write non-trivial ROS 2 code, including custom messages, lifecycle
nodes, TF2 broadcasters, and Nav2 conguration.
Why? → Big
idea → Analogy → Mechanism → Worked example
Every section follows the ve-step teaching arc you saw in Modules 3 and 5:
. The Smart Autonomous Industrial
Inspection Robot threads through every section as the running example.
Contents
1 Why ROS 2 Exists A Short History 4
1.1 The Pre-ROS Chaos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 The Birth of ROS (2007) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Why ROS 1 Was Not Enough . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 The ROS 2 Redesign (Released 2017) . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5 ROS 2 Distributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 DDS The Middleware That Powers ROS 2 5
2.1 What is DDS? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 How Discovery Works (No Master) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Multiple RMW Implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3 The Computational Graph Nodes, Topics, Services, Actions 6
3.1 The Five Primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 When to Use Which . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Dept. of Mechatronics & Automation Engg., NIT Patna Page 1
MAE41115 | Module 4 ROS 2 From Concepts to Production
3.3 A Minimal Talker / Listener Pair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.4 Inspecting the Graph at Runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4 Messages and Interfaces 8
4.1 Why Typed Messages? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2 The Three Interface File Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.3 Standard Field Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.4 A Custom Message: [Link] . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.5 A Custom Service: [Link] . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.6 A Custom Action: [Link] . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.7 Building the Interface Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5 Quality of Service in Depth 10
5.1 Why QoS Matters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.2 The Seven Policies You Must Know . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.3 The Compatibility Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.4 Built-in Proles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
6 Parameters and Launch Files 11
6.1 Parameters The Right Way to Congure a Node . . . . . . . . . . . . . . . . . . . 12
6.1.1 Declaring with Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.1.2 Reading and Reacting to Changes . . . . . . . . . . . . . . . . . . . . . . . . 12
6.1.3 Setting from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.2 Launch Files Orchestrating Multiple Nodes . . . . . . . . . . . . . . . . . . . . . . 12
6.2.1 A Minimal Launch File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.2.2 Running with Overrides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
7 Lifecycle (Managed) Nodes 13
7.1 Why Lifecycle Nodes? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
7.2 The State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
7.3 Skeleton of a Lifecycle Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
7.4 Driving Transitions Externally . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8 Composition Many Nodes, One Process 15
8.1 Why Composition? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
8.2 Making a Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
8.3 Running Multiple Nodes in One Container . . . . . . . . . . . . . . . . . . . . . . . . 15
9 Time, TF2 and Coordinate Frames 16
9.1 Two Clocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
9.2 Coordinate Frames Are Everywhere . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
9.3 Tree Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
9.4 Broadcasting and Listening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
10 URDF Describing Your Robot 18
10.1 Why URDF? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
10.2 Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
10.3 Xacro The Macro Language for URDF . . . . . . . . . . . . . . . . . . . . . . . . 19
11 Navigation Stack (Nav2) 19
11.1 What Nav2 Does . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
11.2 The Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
11.3 Behaviour Trees in 30 Seconds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Dept. of Mechatronics & Automation Engg., NIT Patna Page 2
MAE41115 | Module 4 ROS 2 From Concepts to Production
12 Security, Tooling and Best Practice 21
12.1 SROS2 Secure ROS 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
12.2 The Five Tools You Will Use Daily . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
12.3 Workspace and colcon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
13 A Complete Worked Project Inspection Robot Perception Node 22
13.1 What We Build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
13.2 Custom Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
13.3 Lifecycle Node Skeleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
13.4 Launch File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
13.5 Building and Running on the Jetson . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
14 GATE-Style Practice Problems 24
15 Summary in One Slide 25
Dept. of Mechatronics & Automation Engg., NIT Patna Page 3
MAE41115 | Module 4 ROS 2 From Concepts to Production
1 Why ROS 2 Exists A Short History
1.1 The Pre-ROS Chaos
Before about 2007, every robotics lab wrote its software from scratch. A PhD student would spend a
year writing a driver for the laser scanner, another year writing a driver for the wheels, another year
writing the path planner, and only in the fourth year actually demonstrate something interesting.
When that student graduated, the next student inherited a codebase that worked only on their robot
and threw it away to start over. The eld moved at a glacial pace.
1.2 The Birth of ROS (2007)
Researchers at Stanford, then at Willow Garage (a research outt in Silicon Valley funded by Scott
infrastructure,
R O S
Hassan), realised that the bottleneck was not algorithms. They built ROS the
obot perating ystem (the name is misleading: it is not an OS, it runs on top of Linux) as
an open-source meta-framework. ROS provided:
A common message-passing layer, so any laser driver could feed any path planner.
Standard message types (sensor_msgs/LaserScan, geometry_msgs/Twist, etc.).
Tools for visualisation (RViz), recording (rosbag), and teleoperation.
A package system: apt-get install ros-noetic-navigation and you had a navigation
stack.
ROS 1 became wildly successful in research and education. PR2, Baxter, TurtleBot, the entire
DARPA Robotics Challenge all on ROS.
1.3 Why ROS 1 Was Not Enough
But ROS 1 had three deal-breakers for industrial deployment:
1. Single point of failure. Every node registered with a central process called the roscore (or
master). If the master died, the entire robot died. Industry will not accept that.
2. No real-time. The transport was a custom TCP/UDP layer with no quality-of-service guar-
antees. A slow video subscriber could starve a control message.
3. No security. Anyone on the network could publish to any topic. The dashboard intern could
accidentally drive the robot into a wall.
1.4 The ROS 2 Redesign (Released 2017)
DDS (Data
Distribution Service)
The ROS team started over. They threw out the custom transport and adopted
a battle-tested industrial middleware used in air-trac control, NASA
missions, and naval combat systems. DDS gave them peer-to-peer discovery (no master), built-
in QoS, and security. They redesigned the API to support real-time, multi-robot, and embedded
deployments. The rst stable distribution shipped in 2017; today's distributions (Iron, Jazzy, Kilted,
Rolling) are mature production tools used by companies including Bosch, Sony, NASA, and the US
Navy.
The big idea of ROS 2
ROS 2 is a peer-to-peer publish/subscribe robotics middleware built on DDS, with rst-class
support for real-time, multi-robot coordination, and security. It denes a small set of core
abstractions (nodes, topics, services, actions, lifecycle), a rich library of standard message
Dept. of Mechatronics & Automation Engg., NIT Patna Page 4
MAE41115 | Module 4 ROS 2 From Concepts to Production
types, and an ecosystem of tools (RViz2, rqt, ros2bag, Nav2, MoveIt2) that work together.
Common Pitfall
ROS 2 only
This module covers . ROS 1 is end-of-life as of May 2025 (nal distribution Noetic).
Any tutorial mentioning rosrun, roslaunch, roscore, rospy, or XML-RPC is outdated. Use
ros2 run, ros2 launch, no master,rclpy/rclcpp, and DDS.
1.5 ROS 2 Distributions
Like Ubuntu, ROS 2 ships in named distributions, alternating long-term and short-term support:
Distro Released Support
Foxy Fitzroy 2020 EOL
Humble Hawksbill 2022 LTS until 2027
Iron Irwini 2023 EOL
Jazzy Jalisco 2024 LTS until 2029
Kilted Kaiju 2025 18 months
Rolling continuous development
For deployment use an LTS distribution (Humble or Jazzy). Our Jetson Orin Nano runs Jazzy
on Ubuntu 24.04.
2 DDS The Middleware That Powers ROS 2
2.1 What is DDS?
Data Distribution Service (DDS) is an OMG (Object Management Group) standard for real-
time publish/subscribe data exchange. It started in defence and avionics; ROS 2 adopted it because
it solves all the problems ROS 1's transport had:
Decentralised peer-to-peer discovery (no master, no single point of failure).
Multiple QoS policies (reliability, durability, deadline, lifespan, history).
Multicast and unicast transports.
Built-in security framework (DDS Security).
RMW
Multiple competing implementations from dierent vendors ROS 2 abstracts over them via
the (ROS Middleware) layer.
2.2 How Discovery Works (No Master)
When a ROS 2 node starts up, it sends a multicast announcement: Hello, I am node X, I publish
on topic /f oo with type T and QoS Q. Other nodes on the network receive this and update
their internal directories. When a publisher and a subscriber discover each other and their QoS is
compatible, DDS sets up a direct point-to-point or multicast connection between them. From then
on, data ows directly no broker, no master.
The postal system vs a single switchboard
ROS 1's master was like an old village telephone exchange: every call went through one operator
who connected you to the right person. If the operator went home, the entire village went silent.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 5
MAE41115 | Module 4 ROS 2 From Concepts to Production
DDS is more like the postal system: every house has an address, anyone can drop a letter
directly into your letterbox, and the post oce is invisible plumbing. There is no central
switchboard. If your neighbour moves house, only you and they need to know the new address;
the rest of the village carries on as before.
ROS 2's removal of the master is exactly this transition: from a switchboard to a postal system.
2.3 Multiple RMW Implementations
You can swap the underlying DDS vendor with a single environment variable:
$ export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # Eclipse Cyclone DDS (default in
Humble)
$ export RMW_IMPLEMENTATION=rmw_fastrtps_cpp # eProsima Fast DDS
$ export RMW_IMPLEMENTATION=rmw_connext_cpp # RTI Connext (commercial)
For most students the default is ne. For production deployments you may pick a specic vendor
for performance, support, or feature reasons (Cyclone DDS, for instance, is famous for low latency
on embedded systems).
Inspection-Robot Connection
Our inspection robot's Jetson Orin Nano runs Cyclone DDS. The robot has its own ROS 2
domain ID (set via ROS_DOMAIN_ID=42) so its DDS trac is isolated from any other ROS 2
systems on the same plant network. The MEC server, when it acts as a ROS 2 client, joins
the same domain.
3 The Computational Graph Nodes, Topics, Services, Actions
3.1 The Five Primitives
ROS 2 organises a robot's software into a runtime graph of communicating components. There are
ve primitive ideas:
Primitive What it is
Node A process (or composable component) with a unique fully-qualied name. Owns publishers,
subscribers, services, parameters.
Topic A named channel on which messages of a xed type ow. Many-to-many.
Service A blocking request/response call between exactly one client and one server.
Action A long-running goal with periodic feedback and a nal result. Cancellable.
Parameter A named, typed runtime conguration value (string, int, bool, list, etc.).
Dierent ways of getting in touch
topic
A is a WhatsApp group. Anyone can post; everyone in the group sees the post;
nobody waits for a reply.
service
A is a phone call. You ring up, ask a specic question, the other side answers,
you hang up.
action
An is ordering pizza. You place an order (the goal), the shop sends periodic
updates (starting prep, in the oven, out for delivery) that's feedback and
nally the pizza arrives (the result). You can cancel mid-way.
A node is a person. Has a name, can be on multiple WhatsApp groups, can make and
Dept. of Mechatronics & Automation Engg., NIT Patna Page 6
MAE41115 | Module 4 ROS 2 From Concepts to Production
receive phone calls, can place orders.
A parameter is a setting on the person's phone ringer volume = 70%, changeable
by the user, persistent.
3.2 When to Use Which
A common student question. The decision tree:
Use . . . When . . .
Topic Data ows continuously, many subscribers, no reply needed (sensor streams, joint states, status).
Service A short, blocking computation with one answer (what is the kinematic model name?, set the
gripper open/closed).
Action A long-running goal with progress (navigate to (x, y), follow this trajectory).
Parameter Conguration knob set at startup or by a tool, not a control signal.
Common Pitfall
Beginners often use services for everything because services feel familiar (it's a function call).
Topics are the default.
Resist this. Services block the client until the server replies. If your control loop calls a service
every cycle, your control loop now waits on the network. Services
are exceptions for one-shot cong-style operations.
3.3 A Minimal Talker / Listener Pair
The classic rst program in any ROS 2 tutorial: one node publishes, another subscribes.
Listing 1: [Link] publishes Hello %d on topic /chatter every second.
import rclpy
from [Link] import Node
from std_msgs.msg import String
class Talker(Node):
def __init__(self):
super().__init__('talker')
[Link] = self.create_publisher(String, 'chatter', 10)
[Link] = self.create_timer(1.0, [Link])
[Link] = 0
def tick(self):
msg = String()
[Link] = f'Hello {[Link]}'
[Link](msg)
self.get_logger().info(f'Published: {[Link]}')
[Link] += 1
def main():
[Link]()
[Link](Talker())
[Link]()
Listing 2: [Link] subscribes to the same topic.
import rclpy
from [Link] import Node
from std_msgs.msg import String
Dept. of Mechatronics & Automation Engg., NIT Patna Page 7
MAE41115 | Module 4 ROS 2 From Concepts to Production
class Listener(Node):
def __init__(self):
super().__init__('listener')
self.create_subscription(String, 'chatter', [Link], 10)
def cb(self, msg):
self.get_logger().info(f'Heard: {[Link]}')
def main():
[Link]()
[Link](Listener())
[Link]()
3.4 Inspecting the Graph at Runtime
Once the nodes are running, the ros2 CLI lets you introspect the live graph:
$ ros2 node list # see all running nodes
$ ros2 topic list # see all topics being published
$ ros2 topic info /chatter # publishers, subscribers, type, QoS
$ ros2 topic echo /chatter # print live messages
$ ros2 topic hz /chatter # measured publish rate
$ ros2 topic bw /chatter # measured bandwidth
$ ros2 node info /talker # everything node /talker exposes
These six commands are 80 % of debugging a ROS 2 system. Master them.
Worked Example 4.3.1 Topic Bandwidth Calculation
Setting. sensor_msgs/PointCloud2
A LiDAR publishes at 20 Hz. Each scan has 65 000
points, and each point is 16 B (XYZ + intensity, all oat32 + padding). Compute the topic
bandwidth.
Step 1 Per-message size.
65 000 points × 16 B/point = 1 040 000 B ≈ 1.04 MB
Step 2 Add header overhead. sensor_msgs/PointCloud2 has ∼200 B of xed header
Step 3 Bandwidth at 20Hz.
(frame ID, timestamp, elds metadata). Negligible.
1.04 × 106 × 20 = 2.08 × 107 B/s = 166 Mbit/s
Step 4 Implication. On the Jetson, sending this from the LiDAR driver to the perception
across DDS serialisation
composition
node would dominate the CPU. The x: run both nodes inside a single
process using (Section 9), so the message travels as an in-process pointer instead
of being serialised.
4 Messages and Interfaces
4.1 Why Typed Messages?
In ROS 2 you cannot just send raw bytes between nodes. Every topic, service, and action is associated
with a typed interface dened in a small declarative language. The build system generates type-safe
code in C++ and Python from these denitions. This means a publisher and subscriber that disagree
on the type fail at startup, not silently in the middle of a deployment.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 8
MAE41115 | Module 4 ROS 2 From Concepts to Production
4.2 The Three Interface File Types
Sux Use Structure
.msg Topic message A at sequence of typed elds.
.srv Service Two sections (request and response) separated by -.
.action Action Three sections (goal, result, feedback) separated by -.
4.3 Standard Field Types
Type Notes
bool, byte, char Single primitives
int8, int16, int32, int64 Signed integers
uint8, uint16, uint32, uint64 Unsigned integers
float32, float64 IEEE 754
string, wstring UTF-8 / UTF-16
T[], T[N], T[≤N] Unbounded, xed-length, bounded sequences
builtin_interfaces/Time Time stamps
geometry_msgs/Pose Common composite type
4.4 A Custom Message: [Link]
# pump_msgs/msg/[Link]
std_msgs/Header header # timestamp + frame_id
string pump_id # "Pump_3"
float32 discharge_temp_c
float32 discharge_pressure_bar
float32[3] vibration_rms_mm_s # X, Y, Z
uint8 status # constants below
uint8 STATUS_OK = 0
uint8 STATUS_WARN = 1
uint8 STATUS_ALARM = 2
4.5 A Custom Service: [Link]
# pump_msgs/srv/[Link]
string operator_id # who is requesting the reset
---
bool success
string message
uint32 cycles_before_reset
The - divides the request (above) from the response (below).
4.6 A Custom Action: [Link]
# pump_msgs/action/[Link]
# Goal
string pump_id
float32 inspection_duration_s
---
# Result
bool success
Dept. of Mechatronics & Automation Engg., NIT Patna Page 9
MAE41115 | Module 4 ROS 2 From Concepts to Production
PumpHealth final_report
---
# Feedback
float32 percent_complete
string current_phase # "approaching", "scanning", "analysing"
The two - dividers separate goal, result, and feedback. The result is sent once when the action
completes; feedback is published periodically while the action is in progress.
4.7 Building the Interface Package
Listing 3: pump_msgs/[Link] key fragment.
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/[Link]"
"srv/[Link]"
"action/[Link]"
DEPENDENCIES std_msgs builtin_interfaces
)
After colcon build you can use the message in any other package by declaring <depend>pump_msgs</depend>
in its [Link].
Inspection-Robot Connection
The pump_msgs/PumpHealth message is the lingua franca between every node that touches
pump data on our robot the Modbus reader, the anomaly detector, the MQTT bridge, the
RViz visualiser. By putting all the elds a downstream consumer might need (timestamp, ID,
temperature, pressure, vibration, status) in one place, we avoid the temptation to publish four
separate topics that consumers must time-synchronise themselves.
5 Quality of Service in Depth
5.1 Why QoS Matters
In ROS 1, every topic was reliable, ordered, and best-eort to keep up. There was no choice. ROS
2 inherits DDS's QoS, which lets you choose but requires you to choose. Get it wrong, and your
dashboard never shows messages, your sensor stream backs up, or your safety-critical command
silently drops.
5.2 The Seven Policies You Must Know
Policy Choices Eect
Reliability RELIABLE / BEST_EFFORT TCP-like vs UDP-like delivery semantics.
Durability TRANSIENT_LOCAL / VOLATILE Late subscribers see past messages or only future ones.
History KEEP_LAST(n) / KEEP_ALL Buer depth at the publisher.
Deadline duration Maximum allowed gap between messages; violations re
callbacks.
Liveliness AUTOMATIC / MANUAL_BY_TOPIC How the publisher signals I am alive.
Lifespan duration Discard messages older than this from the queue.
Lease Duration duration Time after which a publisher is deemed dead if no liveli-
ness.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 10
MAE41115 | Module 4 ROS 2 From Concepts to Production
5.3 The Compatibility Rule
A subscriber can connect to a publisher only if the publisher's QoS is at least as strong as the
subscriber's request. The mnemonic: the publisher oers, the subscriber requests, the oer must
satisfy the request. If a subscriber asks for RELIABLE but the publisher oers only BEST_EFFORT,
the subscriber is silently disconnected. (ros2 doctor and ros2 topic info -v will tell you why.)
Pub oers Sub requests RELIABLE Sub requests BEST_EFFORT
RELIABLE Yes Yes
BEST_EFFORT No Yes
A subscriber that asks for stronger guarantees than the publisher oers is silently dropped. Use
ros2 topic info -v /your_topic to see which subscribers are connected and which are not.
5.4 Built-in Proles
ROS 2 ships with named proles so you don't have to build them from scratch:
Prole Use case
[Link].qos_profile_default Generic reliable, depth 10. Safe default.
[Link].qos_profile_sensor_data Best-eort, depth 5. For high-rate sensors.
[Link].qos_profile_services_default Reliable, depth 10, for service-style trac.
[Link].qos_profile_parameters For parameter events.
[Link].qos_profile_system_default Whatever the underlying RMW prefers.
Worked Example 4.5.1 Choose QoS for Each Topic
For our inspection robot, decide the QoS for each topic and justify briey.
Topic Choice Justication
/lidar/points BEST_EFFORT, KEEP_LAST 5 High rate; freshest scan more useful
than oldest.
/cmd_vel RELIABLE, KEEP_LAST 1 Losing a velocity command is unsafe.
/joint_states RELIABLE, KEEP_LAST 10 Used by TF; missing samples corrupt
the tree.
/robot_description RELIABLE, TRANSIENT_LOCAL, Published once at startup; late sub-
depth 1 scribers must still receive it.
/system_health RELIABLE + Deadline=1.5 s Heartbeat. Missed deadline triggers
safety callback.
/pump3/vibration BEST_EFFORT, KEEP_LAST 10 Fresh data more valuable than com-
plete data.
/pump3/alert RELIABLE, KEEP_LAST 100, Alerts must arrive but stale alerts are
Lifespan=60 s useless.
Mental model. newer is more useful than complete → BEST_EFFORT. If every message
If
must arrive → RELIABLE. If late subscribers need the last value → TRANSIENT_LOCAL.
6 Parameters and Launch Files
Dept. of Mechatronics & Automation Engg., NIT Patna Page 11
MAE41115 | Module 4 ROS 2 From Concepts to Production
6.1 Parameters The Right Way to Congure a Node
A robot's behaviour depends on dozens of constants: PID gains, sensor thresholds, frame names, le
parameters
paths. Hard-coding them is brittle. Reading them from a cong le is better. ROS 2 standardises
this through .
6.1.1 Declaring with Constraints
Listing 4: Declaring parameters with bounds and descriptions.
from rcl_interfaces.msg import ParameterDescriptor, FloatingPointRange
class AnomalyDetector(Node):
def __init__(self):
super().__init__('anomaly_detector')
self.declare_parameter(
'threshold_g', 5.0,
descriptor=ParameterDescriptor(
description='Vibration RMS alarm threshold in g',
floating_point_range=[FloatingPointRange(
from_value=0.1, to_value=20.0, step=0.1)]))
self.declare_parameter('window_size', 100)
self.declare_parameter('pump_ids', ['Pump_3'])
6.1.2 Reading and Reacting to Changes
Listing 5: Listen for parameter changes at runtime.
def __init__(self):
super().__init__('anomaly_detector')
self.declare_parameter('threshold_g', 5.0)
self.add_on_set_parameters_callback(self.on_params)
def on_params(self, params):
from rcl_interfaces.msg import SetParametersResult
for p in params:
if [Link] == 'threshold_g' and [Link] < 0:
return SetParametersResult(successful=False,
reason='threshold_g must be >= 0')
return SetParametersResult(successful=True)
6.1.3 Setting from the Command Line
$ ros2 run pump_edge anomaly_detector --ros-args -p threshold_g:=6.5
$ ros2 param set /anomaly_detector threshold_g 7.0 # at runtime
$ ros2 param dump /anomaly_detector > [Link] # save current
6.2 Launch Files Orchestrating Multiple Nodes
A real robot has dozens of nodes. Starting them by hand, in the right order, with the right parameters,
is hopeless. ROS 2 launch les are Python scripts that describe what to start.
6.2.1 A Minimal Launch File
Dept. of Mechatronics & Automation Engg., NIT Patna Page 12
MAE41115 | Module 4 ROS 2 From Concepts to Production
Listing 6: launch/[Link] starts three nodes with parameters.
from launch import LaunchDescription
from [Link] import DeclareLaunchArgument
from [Link] import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
threshold_arg = DeclareLaunchArgument(
'threshold', default_value='5.0',
description='Vibration alarm threshold in g')
return LaunchDescription([
threshold_arg,
Node(package='pump_edge', executable='vibration_sensor',
name='vibration_sensor', output='screen'),
Node(package='pump_edge', executable='anomaly_detector',
name='anomaly_detector',
parameters=[{'threshold_g': LaunchConfiguration('threshold')}],
output='screen'),
Node(package='pump_edge', executable='mqtt_bridge',
name='mqtt_bridge', output='screen'),
])
6.2.2 Running with Overrides
$ ros2 launch pump_edge [Link]
$ ros2 launch pump_edge [Link] threshold:=7.5
A launch le is a recipe card
Imagine you are running a small kitchen. A launch le is the recipe card: which dishes to
prepare, in which order, with which ingredients (parameters), all in one document. The chef
(you, the operator) does not memorise the recipe it is written down. When the menu
changes, you edit the recipe card, not the chef 's brain.
7 Lifecycle (Managed) Nodes
7.1 Why Lifecycle Nodes?
In a safety-critical robot, you cannot have nodes silently starting up in random order, allocating
lifecycle nodes
resources, and possibly publishing nonsense before they have congured themselves. You need
explicit, observable startup. ROS 2 oers (also called managed nodes ) for exactly
this.
7.2 The State Machine
Primary state Transitions out Meaning
Uncongured congure → Inactive Node started but no resources allocated.
Inactive activate → Active Resources allocated, but not yet processing data.
Active deactivate → Inactive Processing normally.
shutdown → Finalised Permanently shutting down.
Finalised Terminal.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 13
MAE41115 | Module 4 ROS 2 From Concepts to Production
Each transition has a callback (on_configure, on_activate, on_deactivate, on_cleanup, on_shutdown,
on_error) that you implement.
Trac-light states for a node
Think of lifecycle states like a trac light.
Red (Uncongured) engine o; nothing is allocated.
Red-Amber (Inactive) engine on, ready to go but not driving.
Green (Active) driving.
O (Finalised) the light is shut down for the night.
The supervisor (a person, or another node) ips the light. The intersection (your robot) cannot
accidentally jump from o to green.
7.3 Skeleton of a Lifecycle Node
Listing 7: A lifecycle camera driver.
from [Link] import LifecycleNode, TransitionCallbackReturn, LifecycleState
from [Link] import Publisher
from sensor_msgs.msg import Image
class CameraDriver(LifecycleNode):
def __init__(self):
super().__init__('camera_driver')
[Link] = None
def on_configure(self, state: LifecycleState):
# allocate resources, do not publish yet
[Link] = self.create_lifecycle_publisher(Image, 'image_raw', 10)
[Link] = self.create_timer(0.033, [Link])
[Link]() # stays cancelled until activate
self.get_logger().info('Configured.')
return [Link]
def on_activate(self, state):
[Link]()
return super().on_activate(state) # default flips publisher state
def on_deactivate(self, state):
[Link]()
return super().on_deactivate(state)
def on_cleanup(self, state):
self.destroy_publisher([Link])
self.destroy_timer([Link])
return [Link]
def tick(self):
msg = Image()
# ... fill in image data ...
[Link](msg)
7.4 Driving Transitions Externally
$ ros2 lifecycle list /camera_driver
$ ros2 lifecycle set /camera_driver configure
Dept. of Mechatronics & Automation Engg., NIT Patna Page 14
MAE41115 | Module 4 ROS 2 From Concepts to Production
$ ros2 lifecycle set /camera_driver activate
$ ros2 lifecycle set /camera_driver deactivate
A bring-up script (or Nav2's lifecycle_manager) can congure-and-activate a eet of nodes in
the right order.
Inspection-Robot Connection
On our robot, the perception, navigation, and inspection stacks are all lifecycle nodes man-
aged by Nav2's lifecycle_manager_navigation. The supervisor activates them in the order:
localisation → planner → controller → behaviour-tree-server. If any one fails to congure, the
manager rolls everything back to uncongured the robot never starts up half-baked.
8 Composition Many Nodes, One Process
8.1 Why Composition?
By default, every ROS 2 node runs in its own OS process. That isolates them nicely (a crash in one
does not kill another), but it has a cost: messages between nodes are serialised, sent through DDS,
and de-serialised even if the two nodes are on the same machine. For a 1 Mbps text topic this is
Composition
invisible; for a 200 MB/s point cloud it is catastrophic.
solves this by letting multiple nodes run inside the same process. When a publisher
intra-process communication (IPC)
and subscriber inside the same process are connected, ROS 2 can pass the message as a shared pointer,
skipping serialisation entirely. This is called .
Apartments vs roommates
Each ROS 2 node is normally an apartment with its own kitchen and door. Composition is a
shared house with multiple roommates: they save kitchen-time (serialisation) by passing dishes
(messages) hand-to-hand. The trade-o is privacy: a re in one roommate's kitchen burns the
whole house, whereas a re in one apartment is contained.
You compose nodes when the speed is worth the shared fate; you keep them in separate
processes when reliability outranks throughput.
8.2 Making a Component
Listing 8: A composable Python node.
import rclpy
from [Link] import Node
from std_msgs.msg import String
from [Link] import MultiThreadedExecutor
class ComposableTalker(Node):
def __init__(self):
super().__init__('composable_talker')
# ... pub, sub, timer ...
# Mark as composable in [Link]:
# entry_points={'console_scripts': ['composable_talker = [Link]:main']}
In C++ the node class is registered with RCLCPP_COMPONENTS_REGISTER_NODE, which lets a
container process load it dynamically.
8.3 Running Multiple Nodes in One Container
Dept. of Mechatronics & Automation Engg., NIT Patna Page 15
MAE41115 | Module 4 ROS 2 From Concepts to Production
Listing 9: Composable launch with intra-process comms.
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
def generate_launch_description():
container = ComposableNodeContainer(
name='perception_container',
namespace='',
package='rclcpp_components',
executable='component_container_mt',
composable_node_descriptions=[
ComposableNode(
package='lidar_driver', plugin='lidar::Driver',
name='lidar', extra_arguments=[{'use_intra_process_comms': True}]),
ComposableNode(
package='perception', plugin='perception::Filter',
name='filter', extra_arguments=[{'use_intra_process_comms': True}]),
ComposableNode(
package='perception', plugin='perception::Detector',
name='detector', extra_arguments=[{'use_intra_process_comms': True}]),
],
output='screen')
return LaunchDescription([container])
The three nodes share one process, one address space, and one CPU-anity domain. Point
clouds ow between them as raw pointers.
Worked Example 4.8.1 Throughput Gain from Composition
Setting. A 166 Mbit/s LiDAR stream (Example 4.3.1) is consumed by two lters and one
detector. Without composition, every message is serialised once and de-serialised three times.
Without composition. 4 serialise/deserialise cycles per message, each costs ∼2 ms CPU on
the Jetson.
4 × 2 ms × 20 Hz = 160 ms/s
16% of one CPU core
With composition + IPC.
That is burnt purely on copy-and-translate.
Same 20 Hz, but only one shared pointer per consumer; cost
∼ µ
Verdict.
drops to 50 ⇒ s each 3 ms/s total ≈ 0.3 % of a core.
∼
Composition recovers 157 ms/s of CPU, freeing it for actual perception work.
9 Time, TF2 and Coordinate Frames
9.1 Two Clocks
A robot has two senses of now:
System (wall) time what your computer's clock says.
ROS time which may equal system time on a real robot, or simulated time when you
replay a ros2bag or run Gazebo.
Set use_sim_time:=true on every node when replaying or simulating, so timestamps from the
bag drive the system rather than wall clock. Forgetting this is the single most common reason a
perfectly recorded log fails to replay.
9.2 Coordinate Frames Are Everywhere
A modern robot has dozens of coordinate frames: map, odom, base_link, laser_link, camera_link,
ee_link, and many more. A LiDAR point published in laser_link means nothing to the navigation
Dept. of Mechatronics & Automation Engg., NIT Patna Page 16
MAE41115 | Module 4 ROS 2 From Concepts to Production
map. Somebody must convert.
TF2
stack, which thinks in
(also called tf2_ros) is the library that maintains the entire tree of transforms between
frames in real time, lets nodes publish updates, and lets consumers look up the transform between
A and B at time t.
Russian dolls of coordinates
Coordinate frames are like a tree of nested dolls.
map is the world.
Inside map sits odom (where the robot thinks it is according to wheels).
Inside odom sits base_link (the robot's body).
Inside base_link sit laser_link, camera_link (sensors mounted on the body).
TF2 is the bookkeeper that knows where every doll is relative to its parent, and can therefore
answer where is laser_link in map? by composing the chain.
9.3 Tree Rules
A TF2 tree is a tree, not a graph. Every frame has exactly one parent except the root. There are
exactly two trees in a typical setup:
Static parts of the robot (sensor mounts, wheels) published once by a static_transform_publisher.
Dynamic parts (the robot's pose in map, joint angles) published continuously by localisation,
odometry, and joint-state broadcasters.
9.4 Broadcasting and Listening
Listing 10: Broadcasting a transform.
from tf2_ros import TransformBroadcaster
from geometry_msgs.msg import TransformStamped
class OdomBroadcaster(Node):
def __init__(self):
super().__init__('odom_broadcaster')
[Link] = TransformBroadcaster(self)
self.create_timer(0.05, [Link])
self.x, self.y, [Link] = 0.0, 0.0, 0.0
def tick(self):
t = TransformStamped()
[Link] = self.get_clock().now().to_msg()
[Link].frame_id = 'odom'
t.child_frame_id = 'base_link'
[Link].x = self.x
[Link].y = self.y
# rotation as quaternion (yaw-only here for simplicity)
import math
[Link].z = [Link]([Link]/2)
[Link].w = [Link]([Link]/2)
[Link](t)
Listing 11: Looking up a transform.
from tf2_ros import Buffer, TransformListener
import [Link]
Dept. of Mechatronics & Automation Engg., NIT Patna Page 17
MAE41115 | Module 4 ROS 2 From Concepts to Production
class LaserToMap(Node):
def __init__(self):
super().__init__('laser_to_map')
[Link] = Buffer()
[Link] = TransformListener([Link], self)
self.create_timer(0.1, [Link])
def tick(self):
try:
tf = [Link].lookup_transform(
'map', 'laser_link', [Link](),
timeout=[Link](seconds=0.05))
self.get_logger().info(
f'laser at ({[Link].x:.2f}, '
f'{[Link].y:.2f}) in map')
except Exception as e:
self.get_logger().warn(f'TF lookup failed: {e}')
Worked Example 4.9.1 Forward Kinematics via TF2
Setting. (x, y, θ) = (3.0, 2.0, 30 ) map
The robot's base is at
◦ in . The LiDAR sits on the body
base_link
0.30 m forward of map
. Compute the LiDAR's position in .
Step 1 Static transform base_link → laser_link. A pure translation:
tB→L = (0.30, 0, 0)T
Step 2 Dynamic transform map → base_link. A 2-D rigid:
cos 30◦ − sin 30◦ 3.0 0.866 −0.500 3.0
TM →B = sin 30◦ cos 30◦ 2.0 = 0.500 0.866 2.0
0 0 1.0 0 0 1.0
Step 3 Compose. (0.30, 0) in base_link becomes:
The point
xM 0.30 0.866 × 0.30 + 3.0 3.260
yM = TM →B 0 = 0.500 × 0.30 + 2.0 = 2.150
1 1 1 1
Result. The LiDAR sits at (3.26m, 2.15m) in map. TF2's lookup_transform("map",
"laser_link", ...) does this composition automatically by walking the tree.
10 URDF Describing Your Robot
10.1 Why URDF?
Many tools need to know your robot's geometry: RViz needs to draw it, MoveIt needs to plan
around it, simulators need to physic-it, the TF2 broadcaster needs to know joint limits. Hard-
URDF (Unied Robot Description Format)
coding every link's position into every tool is hopeless. ROS uses a single source of truth: the
an XML le describing the robot's links, joints
and visual/collision/inertial properties.
10.2 Structure
Listing 12: A 2-link arm in URDF.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 18
MAE41115 | Module 4 ROS 2 From Concepts to Production
<?xml version="1.0"?>
<robot name="two_link_arm">
<link name="base">
<visual><geometry><cylinder length="0.1" radius="0.05"/></geometry></visual>
</link>
<link name="link1">
<visual><geometry><box size="0.4 0.05 0.05"/></geometry></visual>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.01" iyy="0.01" izz="0.01" ixy="0" ixz="0" iyz="0"/>
</inertial>
</link>
<link name="link2">
<visual><geometry><box size="0.3 0.05 0.05"/></geometry></visual>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.005" iyy="0.005" izz="0.005" ixy="0" ixz="0" iyz="0"/>
</inertial>
</link>
<joint name="shoulder" type="revolute">
<parent link="base"/>
<child link="link1"/>
<origin xyz="0 0 0.05"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="10" velocity="2"/>
</joint>
<joint name="elbow" type="revolute">
<parent link="link1"/>
<child link="link2"/>
<origin xyz="0.4 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-2.5" upper="2.5" effort="5" velocity="2"/>
</joint>
</robot>
The robot_state_publisher reads this URDF and a stream of joint angles (/joint_states) and
continuously broadcasts the corresponding TF tree. Now RViz, MoveIt, and your collision-checker
all see the same arm.
10.3 Xacro The Macro Language for URDF
Real URDFs are thousands of lines. Xacro adds macros, includes, and parameters so you write
200 lines instead of 5 000. A typical industrial robot URDF is a small my_robot.[Link] that
includes vendor-supplied macros for each joint and gripper.
Inspection-Robot Connection
The inspection robot has two URDFs: one for its mobile base (4 wheels, 1 LiDAR, 1 IMU,
1 RGB-D camera) and one for its 6-DoF inspection arm. They are merged at launch by an
xacro le. The same URDF drives RViz visualisation, Gazebo simulation, MoveIt planning
and the TF tree one source of truth.
11 Navigation Stack (Nav2)
Dept. of Mechatronics & Automation Engg., NIT Patna Page 19
MAE41115 | Module 4 ROS 2 From Concepts to Production
11.1 What Nav2 Does
Nav2 is the ROS 2 navigation stack: a collection of well-tested nodes that, given a map and a goal,
drive a mobile robot from its current pose to the goal while avoiding obstacles. It replaces ROS 1's
move_base.
11.2 The Pipeline
Localisation Costmaps Planner Controller
(AMCL or SLAM) (global & local) (NavFn, Smac- (DWB, MPPI) Behaviour Tree
Planner)
Localisation answers where am I? AMCL (particle lter on a known map) or SLAM
(build the map as we go).
Costmaps mark cells of the world as free / occupied / unknown / inated near obstacles.
There is a slow global costmap and a fast local one.
Planner computes a path in the global costmap from the current pose to the goal.
Controller executes the path, generating velocity commands while avoiding local obstacles.
Behaviour Tree orchestrates the whole pipeline, including recovery behaviours when planning
fails (back up, spin, clear costmap, retry).
11.3 Behaviour Trees in 30 Seconds
A Behaviour Tree (BT) is a hierarchical state machine, born in video-game AI, that has become
the standard way to express robot behaviours. Its leaves are actions (NavigateToPose, Spin, Wait).
Its internal nodes combine children with logic (Sequence, Fallback, Parallel). Nav2's default BT
is a small XML le you can edit without recompiling.
Listing 13: A simplied Nav2 behaviour tree.
<root main_tree_to_execute="MainTree">
<BehaviorTree ID="MainTree">
<Fallback>
<Sequence>
<ComputePathToPose />
<FollowPath />
</Sequence>
<RecoveryActions>
<ClearLocalCostmap />
<Spin />
<BackUp />
</RecoveryActions>
</Fallback>
</BehaviorTree>
</root>
GPS for indoors
Nav2 is essentially Google Maps for an indoor robot. You hand it a map and a goal pin;
it computes a route avoiding walls (planner), drives along it while braking for unexpected
obstacles (controller), reroutes when the way is blocked (recovery), and tells you you have
arrived.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 20
MAE41115 | Module 4 ROS 2 From Concepts to Production
12 Security, Tooling and Best Practice
12.1 SROS2 Secure ROS 2
SROS2
DDS Security gives every ROS 2 node an X.509 certicate, signs every discovery message, and
encrypts trac per topic. The toolchain is called . In a single command:
$ ros2 security create_keystore ~/sros2_keystore
$ ros2 security create_enclave ~/sros2_keystore /robot/talker
$ export ROS_SECURITY_ENABLE=true
$ export ROS_SECURITY_KEYSTORE=~/sros2_keystore
After this, only nodes with valid keystore enclaves can join. Anyone else's trac is dropped.
12.2 The Five Tools You Will Use Daily
Tool Purpose
rqt A Qt-based GUI hosting plugins (graph view, plot, image,
log).
rviz2 3-D visualisation: TF tree, costmaps, point clouds, robot
model.
ros2 bag Record any topic to disk; replay later with original times-
tamps.
ros2 doctor Sanity check: time sync, RMW, network, missing dependen-
cies.
ros2 topic / node / param / lifecycle The CLI Swiss Army knife.
# Record everything for one minute
$ ros2 bag record -a -o lab_session_2026_04_28 -d 60
# Replay the bag (use_sim_time:=true on consumers!)
$ ros2 bag play lab_session_2026_04_28
12.3 Workspace and colcon
A ROS 2 workspace is a directory with three subdirectories that are created and updated by colcon:
Directory Role
src/ Source packages (your code, plus cloned repos).
build/ Intermediate build artifacts.
install/ Final installed binaries, headers, launch les.
log/ Build and test logs.
$ mkdir -p ~/ros2_ws/src && cd ~/ros2_ws
$ cd src && git clone [Link] && cd ..
$ rosdep install --from-paths src --ignore-src -r -y
$ colcon build --symlink-install
$ source install/[Link]
$ ros2 launch pump_edge [Link]
Dept. of Mechatronics & Automation Engg., NIT Patna Page 21
MAE41115 | Module 4 ROS 2 From Concepts to Production
The kitchen revisited
colcon is the head chef of your workspace. src/ is the pantry. colcon build is the call
to cook everything in dependency order the chef gures the order out, you do not say
compile A before B. install/ is the serving counter. source install/[Link] is the
dining-room manager announcing these dishes are now available, so ros2 run can nd them.
symlink-install is the chef 's pro tip: instead of copying the cooked dish to the counter, leave
a symlink. Now editing the recipe (a Python le or launch le) updates the served version
without re-cooking.
13 A Complete Worked Project Inspection Robot Perception
Node
13.1 What We Build
A single composable C++ / Python pipeline that:
1. Subscribes to the LiDAR (/scan) and the RGB-D camera (/camera/depth/points).
2. Filters out points outside the inspection volume (5 m around the robot).
3. Runs a YOLOv8 inference on the camera frame to detect pump/valve/leak.
4. Publishes a custom InspectionReport message on /inspection/report.
5. Acts as a lifecycle node so the bring-up sequence is deterministic.
13.2 Custom Message
# inspection_msgs/msg/[Link]
std_msgs/Header header
string robot_id
geometry_msgs/Pose robot_pose
DetectedObject[] detections
# inspection_msgs/msg/[Link]
string class_name # "pump", "valve", "leak"
float32 confidence # 0..1
geometry_msgs/Point position_in_map
float32 distance_m
13.3 Lifecycle Node Skeleton
import rclpy
from [Link] import LifecycleNode, TransitionCallbackReturn
from [Link] import qos_profile_sensor_data, qos_profile_default
from sensor_msgs.msg import Image, PointCloud2
from inspection_msgs.msg import InspectionReport, DetectedObject
from tf2_ros import Buffer, TransformListener
class PerceptionNode(LifecycleNode):
def __init__(self):
super().__init__('perception_node')
self.declare_parameter('inspection_radius_m', 5.0)
self.declare_parameter('confidence_threshold', 0.6)
self.declare_parameter('robot_id', 'inspector_01')
self.tf_buf = Buffer()
Dept. of Mechatronics & Automation Engg., NIT Patna Page 22
MAE41115 | Module 4 ROS 2 From Concepts to Production
self.tf_lis = TransformListener(self.tf_buf, self)
def on_configure(self, state):
self.report_pub = self.create_lifecycle_publisher(
InspectionReport, '/inspection/report', qos_profile_default)
self.image_sub = self.create_subscription(
Image, '/camera/color/image_raw',
self.on_image, qos_profile_sensor_data)
self.pc_sub = self.create_subscription(
PointCloud2, '/camera/depth/points',
self.on_pointcloud, qos_profile_sensor_data)
[Link] = load_yolov8_model() # pretend
self.get_logger().info('Configured.')
return [Link]
def on_image(self, msg):
if not self._is_active():
return
detections = [Link](msg)
thr = self.get_parameter('confidence_threshold').value
kept = [d for d in detections if [Link] >= thr]
report = self._build_report(kept)
self.report_pub.publish(report)
def on_pointcloud(self, msg):
# filter, segment, classify ...
pass
def _build_report(self, dets):
report = InspectionReport()
[Link] = self.get_clock().now().to_msg()
[Link].frame_id = 'map'
report.robot_id = self.get_parameter('robot_id').value
for d in dets:
obj = DetectedObject()
obj.class_name = [Link]
[Link] = float([Link])
obj.position_in_map = self._to_map_frame([Link])
obj.distance_m = [Link]
[Link](obj)
return report
13.4 Launch File
from launch import LaunchDescription
from launch_ros.actions import LifecycleNode
from [Link] import RegisterEventHandler, EmitEvent
from launch.event_handlers import OnStateTransition
from launch_ros.[Link] import ChangeState
from lifecycle_msgs.msg import Transition
def generate_launch_description():
perception = LifecycleNode(
package='perception', executable='perception_node',
name='perception_node', namespace='',
parameters=[{'inspection_radius_m': 5.0,
'confidence_threshold': 0.65,
'robot_id': 'inspector_01'}],
output='screen')
return LaunchDescription([perception])
Dept. of Mechatronics & Automation Engg., NIT Patna Page 23
MAE41115 | Module 4 ROS 2 From Concepts to Production
13.5 Building and Running on the Jetson
$ cd ~/ros2_ws
$ colcon build --packages-select inspection_msgs perception --symlink-install
$ source install/[Link]
$ ros2 launch perception [Link]
$ ros2 lifecycle set /perception_node configure
$ ros2 lifecycle set /perception_node activate
$ ros2 topic echo /inspection/report
Inspection-Robot Connection
This perception node runs continuously on the inspection robot's Jetson Orin Nano. Reports
are forwarded by an MQTT bridge (Module 5) to the digital twin on the MEC server. The
twin uses each report to update the world model, schedule maintenance jobs, and drive the
SCADA dashboards. The whole pipeline camera frame to twin closes in roughly 180 ms.
14 GATE-Style Practice Problems
Problem 1 Topic vs Service vs Action
For each requirement, choose topic, service, or action and justify in one sentence.
1. Stream IMU data at 200 Hz.
2. Set robot's max speed to a new value.
3. Drive the robot to coordinate (8.5, 3.2).
4. Read the URDF once at startup.
Solution outline.
1. Topic continuous data, many subscribers.
2. Service short, blocking cong change.
3. Action long-running, with feedback and cancellation.
4. Topic with TRANSIENT_LOCAL durability published once but late subscribers must
still receive.
Problem 2 QoS Compatibility
A publisher oers {RELIABLE, KEEP_LAST(10), VOLATILE}; a subscriber requests {RE-
Solution.
LIABLE, KEEP_LAST(20), TRANSIENT_LOCAL}. Will they connect?
not compatible
The subscriber asks for TRANSIENT_LOCAL but the publisher oers only
VOLATILE ⇒ ; subscriber receives nothing. Fix: change publisher to TRAN-
SIENT_LOCAL or relax subscriber to VOLATILE.
Problem 3 TF2 Composition
Frame map→base: translation (2, 1), rotation 45◦ . Frame base→laser: translation (0.2, 0),
rotation 0 . A LiDAR detects an obstacle at (1.0, 0) in laser. Find the obstacle's coordinates
◦
in map.
Solution outline.
Point in base: rotate by 0 and add laser oset ⇒ (1.2, 0).
Point in map: rotate (1.2, 0) by 45◦ ⇒ (0.849, 0.849) then add base oset (2, 1).
Result: (2.849, 1.849) in map.
Dept. of Mechatronics & Automation Engg., NIT Patna Page 24
MAE41115 | Module 4 ROS 2 From Concepts to Production
Problem 4 Composition Speed-up
A pipeline has 4 nodes; each message is serialised once per consumer. With composition + IPC,
serialisation is skipped. If serialisation costs τ ms per consumer and there are 3 consumers, what
Solution.
is the per-message saving as a function of message rate f?
Saving per second = 3τ f ms. For τ = 2 ms and f = 20 Hz: 3 × 2 × 20 = 120 ms/s
of CPU recovered.
Problem 5 Lifecycle Sequencing
A safety-critical robot has three nodes: localizer, planner, controller. Dene a startup
Solution outline.
order using lifecycle transitions and explain why.
Order: congure localizer → activate localizer → congure planner → activate planner
→ congure controller → activate controller.
Reason: planner needs a valid pose from localizer before it can plan; controller needs a path
from planner before it can issue commands. Activating any later node rst risks unsafe motion.
15 Summary in One Slide
Module 4 in One Paragraph
ROS 2 is the modern, peer-to-peer, DDS-based robotics middleware that solved everything
nodes topics, services, and actions
wrong with ROS 1: no master, real-time QoS, security, embedded support. Robot software is
messages .msg .srv .action QoS
decomposed into that communicate via , with strongly
Lifecycle nodes Composition
typed ( , , ). controls reliability, durability, depth, deadline.
TF2 URDF
make startup explicit and observable. lets multiple nodes
Nav2 SROS2
share a process for zero-copy throughput. maintains the tree of coordinate frames;
is the single source of truth for geometry; is the navigation stack. adds X.509-
based security. The colcon workspace, the ros2 CLI, RViz2, rqt and ros2bag are the daily
tools. Our Smart Inspection Robot uses every one of these features composable perception,
lifecycle-managed bring-up, TF2 sensor mounting, URDF-driven simulation, Nav2 navigation,
and an SROS2-secured connection to the MEC server. Module 4 turns a eldbus engineer into
a roboticist.
End of Module 4 Teaching Notes MAE41115, NIT Patna
Dept. of Mechatronics & Automation Engg., NIT Patna Page 25