RWA 1: Robot Fleet Monitor#
Overview#
Due Date |
February 25, 2026, 11:59 PM EST |
Total Points |
30 points |
Submission |
Canvas (ZIP file: |
Collaboration |
Individual work only. AI tools are NOT permitted. |
Late Policy |
10% deduction per calendar day, up to 3 days. Zero after 3 days. |
Description#
You are tasked with building a Robot Fleet Monitor, a Python program that manages and analyzes a fleet of mobile robots. The program will model robot data using Python’s built-in types, process sensor readings, classify robot states, and generate formatted status reports. This assignment tests your understanding of variables, data types, operators, control flow, loops, strings, lists, tuples, and functions (Lectures 1 through 4).
Learning Objectives#
By completing this assignment, you will strengthen and demonstrate the following skills:
Practice using dictionaries, lists, tuples, strings, and numeric types to represent structured data for a robotics application.
Apply conditional logic (if/elif/else) and loops (for/while) to classify data, enforce boundaries, and process collections of robots.
Break a complex problem into well-defined, reusable functions with clear inputs, outputs, type hints, and Google-style docstrings.
Understand how mutable objects (dicts, lists) behave when passed to functions and practice both in-place modification and returning new values.
Use f-strings and string methods to produce clean, aligned, human-readable output from program data.
Develop professional habits including consistent naming conventions, meaningful comments, comprehensive docstrings, and linting compliance.
Structure a Python project across multiple modules, using imports to connect components, reinforcing separation of concerns.
Gain experience modeling a simplified robotics scenario (fleet management, sensor data, battery monitoring) that mirrors patterns found in real-world autonomous systems.
Project Structure#
Your submission must follow the modular project structure shown below. Each module groups related functionality, and main.py imports from the other modules to orchestrate the program.
robot_fleet_monitor/
|-- robot.py # Part 1: Robot data model
|-- sensors.py # Part 2 & 3: Sensor simulation and data analysis
|-- status.py # Part 4: Battery and status classification
|-- report.py # Part 5: Report generation
|-- main.py # Part 6: Main program (entry point)
Module |
Functions |
Description |
|---|---|---|
|
|
Part 1: Builds and validates the robot dictionary |
|
|
Part 2: Generates sensor data and drains battery. Part 3: Computes statistics and classifies readings |
|
|
Part 4: Classifies battery level and updates robot status |
|
|
Part 5: Produces formatted status report string |
|
|
Part 6: Creates fleet, runs pipeline, prints reports and summary |
Note
report.py will need to import compute_statistics and classify_readings from sensors.py, and classify_battery from status.py. Similarly, main.py will import from all other modules. This gives you practice with cross-module dependencies.
Requirements#
Part 1: Robot Data Model (5 pts)#
Module: robot.py
Create a function that builds and returns a robot data structure.
Function: create_robot#
Constructs a dictionary representing a single robot in the fleet. This function initializes the robot with its configuration (name, type, speed, sensors) along with default runtime state (full battery, idle status, and an empty readings list).
def create_robot(name: str, robot_type: str, max_speed: float, sensors: list[str]) -> dict:
Returns a dictionary with the following keys:
"name"(str): the robot’s name"type"(str): the robot type (e.g.,"mobile","arm")"max_speed"(float): the maximum speed in m/s"sensors"(list[str]): a list of sensor names"battery"(float): initialized to100.0"status"(str): initialized to"idle""readings"(list[float]): initialized to an empty list
Important
Validation: If max_speed is negative, set it to 0.0. If sensors is empty, set it to ["default"].
Part 2: Sensor Simulation (5 pts)#
Module: sensors.py
Function: simulate_readings#
Simulates a robot collecting sensor data over time. Each call generates a sequence of readings using a deterministic formula and appends them to the robot’s data, while draining its battery to reflect energy consumption during sensing operations.
def simulate_readings(robot: dict, num_readings: int, base_value: float, variation: float) -> None:
The
robotparameter is the dictionary created bycreate_robot()in Part 1.- Generates
num_readingssensor readings and appends them torobot["readings"]. Each reading is computed as:
base_value + (variation * ((i % 5) - 2))whereiis the loop index (0-based).
- Generates
Each reading should be rounded to 2 decimal places.
For each reading generated, decrease
robot["battery"]by0.5(battery cannot go below0.0).This function modifies the robot dictionary in place and returns
None.
Worked Example
Suppose you create a robot and then call simulate_readings:
robot = create_robot("TurtleBot3", "mobile", 0.26, ["lidar", "camera", "imu"])
simulate_readings(robot, 5, 2.5, 0.5)
Before the call, the dictionary looks like this:
{
"name": "TurtleBot3",
"type": "mobile",
"max_speed": 0.26,
"sensors": ["lidar", "camera", "imu"],
"battery": 100.0,
"status": "idle",
"readings": []
}
During the call, with base_value=2.5, variation=0.5, and num_readings=5, the formula base_value + (variation * ((i % 5) - 2)) produces:
i |
(i % 5) - 2 |
Calculation |
Reading |
|---|---|---|---|
0 |
-2 |
|
1.5 |
1 |
-1 |
|
2.0 |
2 |
0 |
|
2.5 |
3 |
1 |
|
3.0 |
4 |
2 |
|
3.5 |
Each reading also drains the battery by 0.5, so after 5 readings the battery drops from 100.0 to 97.5.
After the call, the dictionary has been modified in place:
{
"name": "TurtleBot3",
"type": "mobile",
"max_speed": 0.26,
"sensors": ["lidar", "camera", "imu"],
"battery": 97.5,
"status": "idle",
"readings": [1.5, 2.0, 2.5, 3.0, 3.5]
}
Notice that simulate_readings does not return anything. It modifies the original robot dictionary directly because dictionaries are mutable objects (pass-by-assignment).
Part 3: Data Analysis (6 pts)#
Module: sensors.py
Function: compute_statistics#
Analyzes a list of sensor readings and computes basic descriptive statistics. This function must calculate the average, minimum, and maximum values using manual iteration rather than built-in functions, reinforcing your understanding of loops and accumulators.
def compute_statistics(readings: list[float]) -> tuple[float, float, float]:
Takes a list of sensor readings.
Returns a tuple of
(average, minimum, maximum), each rounded to 2 decimal places.If the list is empty, return
(0.0, 0.0, 0.0).
Warning
Constraint: Do NOT use the built-in min(), max(), or sum() functions. Use a loop to compute these values manually.
Function: classify_readings#
Categorizes each sensor reading into one of three bins (low, normal, or high) based on user-defined thresholds. This simulates a common pattern in robotics where raw sensor data is converted into meaningful operational categories.
def classify_readings(readings: list[float], low: float, high: float) -> dict[str, list[float]]:
Classifies each reading into one of three categories based on thresholds:
"low": reading <low"normal":low<= reading <=high"high": reading >high
Returns a dictionary with keys
"low","normal","high", each mapping to a list of readings in that category.
Part 4: Status Classification (4 pts)#
Module: status.py
Function: classify_battery#
Maps a numeric battery level to a human-readable status label. This function uses threshold-based classification to determine whether the battery is full, moderate, low, or critical.
def classify_battery(battery: float) -> str:
Returns a status string based on the battery level:
battery >= 80: return"FULL"50 <= battery < 80: return"MODERATE"20 <= battery < 50: return"LOW"battery < 20: return"CRITICAL"
Function: update_robot_status#
Determines the robot’s operational state based on its current battery level. The function calls classify_battery() internally and then updates the robot’s status to reflect whether it can continue operating, should remain idle, or needs to return to base for recharging.
def update_robot_status(robot: dict) -> None:
The
robotparameter is the dictionary created bycreate_robot()in Part 1.Calls
classify_battery()to determine the battery classification, then updatesrobot["status"]accordingly:"FULL"or"MODERATE": set status to"active""LOW": set status to"idle""CRITICAL": set status to"returning to base"
This function modifies the robot dictionary in place and returns
None.
Worked Example
Suppose a robot has been through several sensor simulations and its battery has dropped to 35.0:
robot = {
"name": "TurtleBot3",
"type": "mobile",
"max_speed": 0.26,
"sensors": ["lidar", "camera", "imu"],
"battery": 35.0,
"status": "idle",
"readings": [1.5, 2.0, 2.5, 3.0, 3.5]
}
update_robot_status(robot)
Inside the function, classify_battery(35.0) returns "LOW" (since 20 <= 35.0 < 50), so the function sets robot["status"] to "idle".
After the call:
robot["status"] # "idle"
If the battery were 85.0 instead, classify_battery(85.0) would return "FULL", and the status would be set to "active". If the battery were 10.0, the classification would be "CRITICAL" and the status would become "returning to base".
Part 5: Report Generation (5 pts)#
Module: report.py
Function: generate_report#
Builds a complete, formatted status report for a single robot by combining its configuration, battery status, sensor statistics, and reading classifications into a multi-line string. This function integrates the outputs of compute_statistics, classify_readings, and classify_battery to produce a human-readable summary.
def generate_report(robot: dict) -> str:
Returns a formatted multi-line string report. Use f-strings for formatting. The report must follow the format shown below. The values shown are illustrative; your output will differ based on the robots you create and the simulation parameters you use.
========================================
ROBOT STATUS REPORT
========================================
Name : TurtleBot3
Type : mobile
Status : active
Battery : 85.00% [FULL]
Max Speed : 0.26 m/s
Sensors : lidar, camera, imu
----------------------------------------
SENSOR READINGS SUMMARY
----------------------------------------
Total Readings : 10
Average : 2.50
Minimum : 1.50
Maximum : 3.50
----------------------------------------
READING CLASSIFICATION (low=1.5, high=3.0)
----------------------------------------
Low : 2 readings
Normal : 5 readings
High : 3 readings
========================================
Use thresholds
low=1.5andhigh=3.0for reading classification inside the report. These thresholds represent boundaries for expected sensor behavior:Readings below
1.5suggest a weak signal or sensor underperformance.Readings between
1.5and3.0(inclusive) fall within the normal operating range.Readings above
3.0may indicate an anomaly such as obstacle proximity or sensor saturation.
The sensors list should be displayed as a comma-separated string.
Battery should display with 2 decimal places followed by the classification in brackets.
If the robot has no readings, the summary section should display
0for all values.
Part 6: Main Program (5 pts)#
Module: main.py
Create a main() function that orchestrates the entire program. Call it from an if __name__ == "__main__" guard. All program logic must live inside main(), not at the module level. Import the necessary functions from robot, sensors, status, and report modules.
The main() function must:
Create at least 3 robots with different configurations using
create_robot().Store the robots in a list.
Simulate readings for each robot using a
forloop with differentbase_valueandvariationparameters.Update each robot’s status using
update_robot_status().Print the report for each robot using
generate_report().After all reports, print a fleet summary showing:
Total number of robots
Number of robots in each status category (active, idle, returning to base)
The robot with the lowest battery level (print its name and battery percentage)
Example Output
The following is an example of what the full program output might look like when run with 3 robots. Your exact values will differ based on the robots you create and the simulation parameters you choose.
========================================
ROBOT STATUS REPORT
========================================
Name : TurtleBot3
Type : mobile
Status : active
Battery : 95.00% [FULL]
Max Speed : 0.26 m/s
Sensors : lidar, camera, imu
----------------------------------------
SENSOR READINGS SUMMARY
----------------------------------------
Total Readings : 10
Average : 2.50
Minimum : 1.50
Maximum : 3.50
----------------------------------------
READING CLASSIFICATION (low=1.5, high=3.0)
----------------------------------------
Low : 2 readings
Normal : 5 readings
High : 3 readings
========================================
========================================
ROBOT STATUS REPORT
========================================
Name : Jackal
Type : mobile
Status : active
Battery : 85.00% [FULL]
Max Speed : 2.00 m/s
Sensors : lidar, gps
----------------------------------------
SENSOR READINGS SUMMARY
----------------------------------------
Total Readings : 30
Average : 5.00
Minimum : 3.00
Maximum : 7.00
----------------------------------------
READING CLASSIFICATION (low=1.5, high=3.0)
----------------------------------------
Low : 0 readings
Normal : 6 readings
High : 24 readings
========================================
========================================
ROBOT STATUS REPORT
========================================
Name : UR5
Type : arm
Status : returning to base
Battery : 10.00% [CRITICAL]
Max Speed : 1.00 m/s
Sensors : force_torque, camera
----------------------------------------
SENSOR READINGS SUMMARY
----------------------------------------
Total Readings : 180
Average : 1.00
Minimum : 0.00
Maximum : 2.00
----------------------------------------
READING CLASSIFICATION (low=1.5, high=3.0)
----------------------------------------
Low : 72 readings
Normal : 108 readings
High : 0 readings
========================================
========================================
FLEET SUMMARY
========================================
Total Robots : 3
Active : 2
Idle : 0
Returning : 1
----------------------------------------
Lowest Battery : UR5 (10.00%)
========================================
Grading Rubric#
Component |
Points |
Criteria |
|---|---|---|
Part 1: Robot Data Model |
5 |
Correct dictionary structure with all keys (2 pts). Input validation for max_speed and sensors (2 pts). Proper type hints in function signature (1 pt). |
Part 2: Sensor Simulation |
5 |
Correct reading formula and rounding (2 pts). Battery drain logic with floor at 0.0 (2 pts). In-place modification of robot dictionary (1 pt). |
Part 3: Data Analysis |
6 |
|
Part 4: Status Classification |
4 |
|
Part 5: Report Generation |
5 |
Exact format match with proper alignment (2 pts). Correct use of f-strings with formatting specifiers (1 pt). Integration of |
Part 6: Main Program |
5 |
Creates 3+ robots and stores in a list (1 pt). Correct loop to simulate, update, and report (2 pts). Fleet summary with status counts and lowest battery (2 pts). |
TOTAL |
30 |
Code Quality Requirements#
Warning
The following are mandatory and will result in point deductions if missing.
Docstrings: Every function must have a Google-style docstring with a description,
Argssection, andReturnssection.Type hints: All function parameters and return types must have type annotations.
Inline comments: Include comments that explain non-obvious logic (e.g., the reading formula, battery drain, threshold classification).
Naming conventions: Use
snake_casefor all function and variable names. Function names must start with a verb.No global variables: All data should be passed through function parameters and return values.
Linting: Ensure Ruff is enabled in VS Code and that no linting errors or warnings appear. You can also run
ruff checkfrom the terminal as a final check.
Deductions
Missing docstrings (-1 pt per function, up to -5 pts). Missing type hints (-0.5 pt per function, up to -3 pts). Poor or missing comments (-1 pt). Naming violations (-1 pt). Linting errors (-1 pt).
Pre-Submission Checklist#
Before submitting, verify that your project meets all of the following requirements. Each item is graded and missing items will result in point deductions.
Functionality#
☐ The program runs without errors:
python3 main.py☐ All 8 functions produce correct output for the given specifications.
☐ The report format matches the expected output (alignment, spacing, delimiters).
☐ The fleet summary displays status counts and the robot with the lowest battery.
Code Quality#
☐ Type hints: Every function parameter and return type has a type annotation (e.g.,
def create_robot(name: str, ...) -> dict:).☐ Docstrings: Every function has a Google-style docstring with a one-line description,
Argssection, andReturnssection.☐ Inline comments: Non-obvious logic is explained with comments (e.g., the reading formula, battery floor, threshold meaning).
☐ Naming: All functions and variables use
snake_case. Function names start with a verb (e.g.,create_,compute_,classify_).☐ No global variables: All data is passed through function parameters and return values. No mutable state at module level.
☐ Imports: Each module uses explicit named imports (e.g.,
from sensors import compute_statistics). No wildcard imports.
Linting#
☐ Ruff is enabled in VS Code and no linting errors or warnings appear in any Python file.
You can also run Ruff from the terminal as a final check:
cd robot_fleet_monitor/
ruff check robot.py sensors.py status.py report.py main.py
File Headers#
☐ Every Python file includes a comment block at the top with your name, UID, and module description.
# Name: <Your Name>
# UID: <Your UID>
# Module: robot.py - Robot data model creation and validation
Packaging#
☐ Removed
__pycache__/,.pyc, and.ruff_cache/before zipping.☐ ZIP file contains only the
robot_fleet_monitor/folder with the five.pyfiles.☐ Verified ZIP contents with
unzip -l.
Before zipping, remove any build artifacts or temporary files that may have been generated:
cd robot_fleet_monitor/
rm -rf __pycache__/ *.pyc .ruff_cache/
cd ..
zip -r robot_fleet_monitor.zip robot_fleet_monitor/
Verify your ZIP has the correct structure by inspecting its contents:
unzip -l robot_fleet_monitor.zip
You should see only the five .py files inside the robot_fleet_monitor/ folder. No __pycache__/, .pyc, or .ruff_cache/ files should be present.
Hints#
Tip
Use
\n(newline) and string concatenation or multi-line f-strings to build the report ingenerate_report().To join a list into a comma-separated string:
", ".join(sensors)Remember that modifying a mutable object (like a dict or list) inside a function affects the original (pass-by-assignment).
Test each function independently before integrating into the main program.
The formula
(i % 5) - 2produces the pattern: -2, -1, 0, 1, 2, -2, -1, 0, 1, 2, …
Submission#
Submit a ZIP file named
robot_fleet_monitor.zipon Canvas.The ZIP must contain a single folder named
robot_fleet_monitor/with exactly five Python files:robot.py,sensors.py,status.py,report.py, andmain.py.The ZIP must not contain
__pycache__/,.pycfiles,.ruff_cache/, or any other build artifacts.The program should run without errors when executed with
python3 main.pyfrom inside therobot_fleet_monitor/directory.Do not submit Jupyter notebooks, extra files, or nested ZIP archives.
Ensure your name and UID are in a comment at the top of every Python file.
Academic Integrity#
Danger
This is an individual assignment. You may not collaborate with other students, share code, or use AI tools (ChatGPT, Copilot, Claude, etc.). You may reference the lecture slides, official Python documentation, and your own class notes. Violations will result in a zero on the assignment and will be reported to the Office of Student Conduct.