Unit 08 · lesson

Java Interfaces and ROS 2 Interfaces: Same Word, Different Contract

The word interface appears in both Java and ROS 2, but it means something different in each system.

That shared vocabulary can be confusing because both ideas involve contracts. A Java interface defines behavior that Java classes agree to provide. A ROS 2 interface defines the structure of data or requests that ROS participants exchange.

The similarity is useful. The difference is essential.

Start with the Java interface you already know

Earlier this week you created:

interface RangeSource {
  String getId();
  double getRangeMeters();
}

This is a Java type contract.

A class can promise to implement it:

class FixedRangeSource implements RangeSource {
  private final String id;
  private final double rangeMeters;

  FixedRangeSource(String id, double rangeMeters) {
    this.id = id;
    this.rangeMeters = rangeMeters;
  }

  @Override
  public String getId() {
    return id;
  }

  @Override
  public double getRangeMeters() {
    return rangeMeters;
  }
}

The compiler checks whether the class provides the methods required by RangeSource.

That contract exists inside the Java type system.

ROS 2 interfaces describe communication data

ROS 2 uses interfaces to describe the data that nodes exchange.

The three main interface categories are:

  • messages, used by topics;
  • services, used for request/response communication;
  • actions, used for longer-running goals that may provide feedback and support cancellation.

For this lesson, focus on a message interface.

Open the official ROS 2 Jazzy Interfaces documentation.

A common sensor message type is:

sensor_msgs/msg/Range

The controlled Robotnix terminal can show its declared fields:

ros2 interface show sensor_msgs/msg/Range

The simulator reports fields including:

std_msgs/Header header
uint8 radiation_type
float32 field_of_view
float32 min_range
float32 max_range
float32 range

Those declarations describe the shape of a ROS message.

For example, the range field is a float32. The message also contains declared minimum and maximum range values and header information.

This is very different from a Java interface method such as:

double getRangeMeters();

The ROS interface defines data that can cross a ROS communication boundary. The Java interface defines methods that Java code can call on an object.

Compare the contracts directly

QuestionJava RangeSourceROS 2 sensor_msgs/msg/Range
What does it define?methods Java implementations must providefields a ROS message contains
Who checks/uses it?Java compiler and Java codeROS 2 type support, publishers, subscribers, tools
Does it create a running component?nono
Can it describe a range value?yes, through a methodyes, through the range field
Is it automatically connected to the other contract?nono

The last row matters most. Similar concepts do not create an integration automatically.

A Java object does not publish a ROS message by existing

Suppose your program creates:

RangeSource source =
    new FixedRangeSource("front", 0.42);

The object can return:

source.getRangeMeters();

with the value:

0.42

That does not mean a ROS 2 message has been published.

For ROS communication to occur, some integration layer must take data from one runtime and produce the appropriate ROS message through a supported ROS implementation.

The course deliberately keeps that boundary visible. A plain Java interface is not a shortcut around the ROS runtime.

Similar data still needs a translation decision

Imagine an integration component receives this Java result:

source.getRangeMeters();  // 0.42

and needs to produce a ROS Range message.

It would need to decide how Java-side information maps to ROS fields such as:

header
radiation_type
field_of_view
min_range
max_range
range

The Java interface currently provides only:

id
rangeMeters

That is not enough information to populate every ROS message field correctly.

This exposes an architecture question instead of hiding it:

What information does the boundary need, and which component owns that information?

The answer might require a richer Java model, configuration, another interface, or a separate adapter. The important point is that the mapping must be designed explicitly.

Inspect one controlled ROS message

Use the controlled terminal and run:

source /opt/ros/jazzy/setup.bash
ros2 interface show sensor_msgs/msg/Range
ros2 topic echo /range --once

The simulated message contains values such as:

header: {stamp: {sec: 42}, frame_id: front_sensor}
min_range: 0.10
max_range: 2.00
range: 0.42

Now separate two observations.

The Java object example contains a stored value of 0.42 meters.

The controlled ROS message example also contains a range field of 0.42.

The matching number does not prove one produced the other. The two examples were intentionally constructed to make comparison easy.

A real integration claim would need evidence of the actual bridge or publisher path.

Message fields carry meaning beyond the number

The ROS message is useful because the range value is not the only information available.

For example:

frame_id: front_sensor

provides frame-related context.

The declared limits:

min_range: 0.10
max_range: 2.00

provide information about the measurement interval represented by the message.

This is why an interface is more than a bag of primitive values. Field names, types, units, and semantics form part of the communication contract.

The same lesson applies to Java interfaces. Method names and return types should communicate what callers may rely on.

Do not confuse a ROS message with a ROS node

Another vocabulary trap is assuming that because a message interface exists, a node using it must also exist.

This command:

ros2 interface show sensor_msgs/msg/Range

shows the definition of an installed interface type.

It does not prove that any current node is publishing a topic of that type.

Similarly, a Java interface can exist in source code even if no object currently implements or uses it at runtime.

Definitions and runtime participation are different questions.

Worked classification

Classify each example by what kind of contract it represents.

Example A

interface MotorCommand {
  void stop();
  void setPercent(double percent);
}

This is a Java interface. It defines methods implementing Java classes must provide.

Example B

geometry_msgs/msg/Twist

This is a ROS 2 message interface type. It defines a message structure used in ROS communication.

Example C

ros2 node list

This is neither kind of interface. It is a runtime graph inspection command.

Example D

class DriveSubsystem extends SubsystemBase

This is a Java class participating in WPILib's subsystem architecture. The class declaration is not a ROS interface.

Keeping the labels precise prevents architecture from collapsing into vocabulary soup.

Practice: design a boundary table

Use your RangeSource interface and the sensor_msgs/msg/Range fields.

Create a table with these columns:

  • Java-side information;
  • possible ROS field;
  • direct mapping, derived value, or missing information;
  • who should own the translation decision.

At minimum, analyze:

getRangeMeters()
getId()
range
frame_id
min_range
max_range
field_of_view

Do not invent values for information your Java contract does not provide. Mark it as missing and explain what additional source would be needed.

In the final lesson, you will use this distinction to review a complete component boundary: what callers can ask in Java, how implementations respond to invalid requests, and what information would still be required before the component could participate in a ROS 2 communication path.