Unit 06 · lab
Lab: Build and Review a Robot Component Class
This lab brings together the Java concepts from the entire chapter: classes, objects, constructors, private state, methods, validation, and component boundaries.
You will build a software model for a front range sensor, test its design with several cases, and then compare the Java model with a ROS 2 runtime observation.
The goal is not to memorize syntax. The goal is to produce a class another programmer could read and understand without guessing what its values mean or which operations are allowed.
Part 1: Start from a weak design
Begin with this class:
class RangeSensor {
public String id;
public double min;
public double max;
public double reading;
}
Before changing anything, identify at least four weaknesses.
Look for problems involving:
- field visibility;
- units;
- required starting information;
- invalid ranges;
- invalid readings;
- unclear public operations.
Record those weaknesses at the top of your Component Model Card.
Part 2: Rewrite the state
Rewrite the fields so that the class stores:
private final String id;
private final String location;
private final double minRangeMeters;
private final double maxRangeMeters;
private double rangeMeters;
Explain why each field is either final or mutable.
A reasonable explanation would distinguish configuration from changing state. The sensor ID, location, minimum, and maximum describe the component configuration. The current reading can change while the object exists.
Part 3: Write the constructor
Create a constructor that requires:
id
location
minimum range in meters
maximum range in meters
Your constructor must reject these invalid cases:
blank id
blank location
negative minimum range
maximum range less than or equal to minimum range
Use IllegalArgumentException for invalid arguments.
A correct constructor should let this object be created:
RangeSensor frontSensor = new RangeSensor(
"front-range",
"front bumper",
0.10,
2.00
);
This case should fail:
RangeSensor brokenSensor = new RangeSensor(
"front-range",
"front bumper",
2.00,
0.10
);
Write one sentence explaining exactly why the second object should be rejected.
Part 4: Protect reading updates
Add this method:
void updateRange(double newRangeMeters)
The method must reject values outside the declared interval.
The important order is:
- check the proposed value;
- reject it if it violates the rule;
- store it only after validation passes.
Do not assign the field first and validate afterward.
Then add:
double getRangeMeters()
and:
boolean isInsideCautionZone(double cautionDistanceMeters)
isInsideCautionZone(...) should return true when the current range is less than the caution distance.
Part 5: Walk through four test cases
Use this object:
RangeSensor frontSensor = new RangeSensor(
"front-range",
"front bumper",
0.10,
2.00
);
Work through these cases in order.
| Case | Operation | Expected result |
|---|---|---|
| A | updateRange(0.42) | accepted |
| B | isInsideCautionZone(0.50) | true |
| C | updateRange(3.70) | rejected |
| D | getRangeMeters() after C | still 0.42 |
For each case, explain why the result follows from your class design.
Case D is especially important. If your method rejects the invalid 3.70 before assignment, the object should preserve the last valid reading.
Part 6: Compare with a WPILib subsystem
Open the official WPILib Subsystems documentation.
Write a short comparison between your RangeSensor class and a WPILib subsystem.
Answer these questions:
- Is every Java class automatically a WPILib subsystem?
- What makes a class participate in WPILib's subsystem architecture?
- Which parts of your
RangeSensorlogic could reasonably live inside a range-sensor subsystem?
Your answer should make clear that Java provides the class/object mechanism while WPILib adds a robotics framework around Java code.
Part 7: Inspect the ROS 2 runtime
The terminal below is a deterministic simulator. It does not execute your Java class and does not connect to a physical robot.
Inspect a Java application beside a ROS 2 Jazzy graph
Source a simulated Jazzy shell, verify the active distribution, inspect nodes and their graph relationships, and keep runtime observations separate from Java and hardware claims.
This is a controlled command simulator. It does not execute Java, ROS 2, shell commands, or network requests on your device.
echo $ROS_DISTROsource /opt/ros/jazzy/setup.bashecho $ROS_DISTROros2 --helpros2 node listros2 node info /sensor_bridgeros2 node info /motor_guardros2 topic listros2 param get /motor_guard caution_distance_m
Run:
source /opt/ros/jazzy/setup.bash
ros2 node list
Record the node names shown by the simulator.
Then answer:
Does creating a
RangeSensorJava object cause one of these ROS 2 nodes to exist?
The correct answer must be based on architecture, not on similar names. A plain Java object and a ROS 2 node belong to different runtime models unless integration code explicitly connects them.
Part 8: Build the Component Model Card
Your final card must contain these sections.
Component purpose
Explain what RangeSensor represents in the Java program.
Fields
For every field, record:
- Java type;
- purpose;
- unit if applicable;
- whether it can change after construction.
Constructor
Show the constructor signature and list the invalid starting states it rejects.
Methods
List each public method and explain what it does.
Invariants
State the rules the class protects.
Test cases
Include the four cases from Part 5 with their expected results.
Architecture classification
State whether your finished class is:
- an ordinary Java class;
- a WPILib subsystem;
- a ROS 2 node;
- or some combination only if the code actually supports that claim.
One limitation
State one thing the class cannot prove about a physical sensor.
Success criteria
Your lab is complete when another student can read the class and answer all of these without guessing:
- What does the object represent?
- What information is required to create it?
- Which values are allowed to change?
- Which invalid states are rejected?
- What methods can outside code call?
- What happens after an invalid update?
- Is this ordinary Java, WPILib architecture, or ROS 2 runtime behavior?
A strong result is not the longest class. It is the class whose rules and responsibility are obvious from the code.