You are a Junior Team Member at ARIITK. The team has three drones — Alpha, Beta, and Gamma. Each drone has a battery level, a name, a status (idle/flying/charging), and a current altitude. Your job is to build a ROS 2 system that simulates all three drones publishing their state, a central fleet manager node that monitors all of them, and package the entire thing inside Docker so any teammate can run it with one command.
Before writing any ROS code, design the drone class structure in pure C++. You need to properly modularize your code using header files (.hpp) and source files (.cpp). Do not write everything in a single file! Your main.cpp should only contain int main() and the necessary setup code.
Class Hierarchy:
Vehicle (abstract base class)
└── Drone (inherits Vehicle)
└── MissionDrone (inherits Drone)
└── AutonomousDrone (inherits MissionDrone)
Custom Exceptions: Define a custom exception hierarchy using C++ standard exception mechanisms. All drone-specific exceptions must share a common base so they can be caught collectively or individually. You will need:
- A base drone exception
- Battery depleted error
- Invalid state error
- Altitude error
Class Requirements:
-
Vehicle(Abstract Base Class)- Attributes:
name(std::string),battery_level(float, 0.0 to 100.0, private),status(std::string, private, only settable through a method that validates allowed states and logs with timestamp),flight_log(std::vector<std::string>, private). - Methods:
get_info()(pure virtual)drain_battery(float amount): reduces battery, never below 0; throwsBatteryDepletedErrorif already at 0.charge_battery(float amount, int duration_seconds): increases battery; throwsInvalidStateErrorif not in charging state.is_critical(): returnsbool.get_flight_log(): returns log as formattedstd::string.- Appropriate getters for all private members (no public setters for battery or status directly).
- Attributes:
-
Drone- Attributes:
altitude(float, protected),max_altitude(float, protected),speed(float, private). - Methods:
take_off(float target_altitude): throwsAltitudeErrorif limit exceeded.land()emergency_stop(): drains battery by 30 as a penalty.- Override
get_info().
- Attributes:
-
MissionDrone- Attributes:
mission_name(std::string),waypoints(std::vector<std::tuple<float, float, float>>),current_waypoint_index(int),visited_waypoints(std::vector<std::pair<std::tuple<float,float,float>, std::string>>, private, stores waypoint + timestamp). - Methods:
next_waypoint(): returns current position as tuple; drains battery by 1.5.skip_waypoint(const std::string& reason)mission_complete(): returnsbool.mission_summary(): returnsstd::string.- Override
get_info().
- Attributes:
-
AutonomousDrone- Attributes:
ai_mode(std::string:"manual","auto","return_home"),home_position(std::tuple<float, float, float>),obstacle_log(std::vector<std::string>, private). - Methods:
set_ai_mode(const std::string& mode):"return_home"inserts home as next waypoint.detect_obstacle(std::tuple<float,float,float> position, const std::string& severity): logs with timestamp; callsemergency_stop()if severity is"high".auto_replan(const std::vector<std::tuple<float,float,float>>& obstacles): returns a new waypoint list avoiding obstacles within 5 units.- Override
get_info().
- Attributes:
main.cpp Requirements:
- Create one object of each class; store them all in a
std::vector<Vehicle*>and callget_info()on each to demonstrate polymorphism. - Show that private members cannot be accessed directly (attempt and explain with a comment).
- Call
drain_battery(),take_off(),detect_obstacle()and catch all exceptions appropriately using the custom exception hierarchy. - Run a full mission on an
AutonomousDrone: take off, iterate all waypoints, simulate a high-severity obstacle, print mission summary. - Use
std::chronofor all timestamps in logs. - Code must compile cleanly with
cmake .. && make(no warnings with-Wall -Wextra).
Make each drone a ROS 2 node written entirely in C++. Build a ROS 2 package drone_fleet containing:
-
Drone Node (
drone_node)- Creates a
MissionDroneobject internally with 5 pre-defined waypoints. - Publishes a
std_msgs/msg/Stringto/drone/<name>/statusevery 1 second. - Message format:
"name:Alpha|battery:87.3|altitude:15.2|status:flying|waypoint:2/5|speed:3.2" - Every publish: drains battery by 0.5; advances waypoint every 3 publishes.
- When battery hits critical: publishes to
/drone/<name>/alertand callsland(). - When mission complete: publishes to
/drone/<name>/mission_completeand restarts mission. - Publishes a JSON-formatted
std_msgs/msg/Stringto/drone/<name>/telemetryevery 2 seconds with full drone state. - Accepts ROS 2 parameters:
drone_name(string),initial_battery(double, default 100.0),mission_name(string).
- Creates a
-
Fleet Manager Node (
fleet_manager)- Subscribes to status (
/drone/<name>/status), alert,mission_complete, and telemetry topics for Alpha, Beta, and Gamma. - Parses the telemetry JSON manually (no external JSON library).
- Every 5 seconds, prints a formatted fleet report table in the console (showing Drone, Battery, Altitude, Waypoint, Status).
- Prints a timestamped warning when any alert arrives.
- Exposes a ROS 2 service
/fleet/status_reportusingstd_srvs/srv/Triggerthat triggers an immediate report.
- Subscribes to status (
-
Health Monitor Node (
health_monitor)- Subscribes to telemetry topics.
- Tracks battery drain rate per drone from the last 10 samples using a circular buffer (
std::deque). - Publishes a warning to
/fleet/health_warningif drain rate exceeds 1.5 per second for any drone. - Every 10 seconds: prints a diagnostics table with drain rate, estimated time to critical, and estimated time to depletion, and publishes a JSON string to
/fleet/health_summary.
-
Launch File (
fleet.launch.py)- Must start:
- Alpha drone node (
initial_battery:=100.0) - Beta drone node (
initial_battery:=60.0) - Gamma drone node (
initial_battery:=35.0- starts nearly critical) - Fleet manager node
- Health monitor node
- Alpha drone node (
- Must start:
Write a Dockerfile and a run.sh script to containerize your workspace.
Dockerfile requirements:
- Base:
osrf/ros:humble-desktop - Copies your entire ROS 2 workspace into the container.
- Builds the workspace with
colcon buildduring image build. - Entrypoint sources ROS 2 and the workspace automatically.
- Uses a multi-stage build: stage 1 (
builder) installs deps and builds; stage 2 (runtime) copies only the install directory. The final image must be under 3 GB.
run.sh script requirements:
- Mount the source code directory as a volume so changes reflect without rebuilding.
- Include necessary flags (like
-it,--rm,--net=host, or-e ROS_DOMAIN_ID=42if required). - The container should automatically run the fleet launch file.
Expected final result:
git clone <your_repo>
cd fleet_ws
chmod +x run.sh
./run.sh
# All five nodes running
# Fleet report every 5 seconds
# Health diagnostics every 10 seconds
# Gamma hits critical within ~30 secondsOpen your Pull Requests (PRs) by June 5 EOD.