Skip to main content

Lesson 7.1: Capstone Specification

The Key Insight​

In professional robotics, this principle is absolute: Specification comes FIRST. Code comes second.

Before you write a single line of Python, before you create a single publisher or service, you define: What is the system supposed to do? What messages flow where? How do we know when success happens?

This lesson teaches you that skill. By the end, you'll have written a complete specification that's so clear, precise, and unambiguous that someone else could implement it—and get the right system.


Why Specs Matter More Than Code​

Think about why this matters for a robot system:

Scenario 1: No Specification

  • You start coding a Navigator node
  • Halfway through, you realize: "Should this take goal requests via service or topic?"
  • You've already written half the code for a service
  • You refactor, lose time, maybe introduce bugs

Scenario 2: Specification First

  • You write: "Navigator accepts goals via /navigate_to service"
  • You implement exactly that
  • No surprises, no refactoring, clear design decision captured
  • Someone else reads your spec and understands your intent

Professional roboticists live by specifications. The goal is clear before implementation starts.


The Specification Template​

Here's the template you'll use. Every line matters—vagueness causes implementation failures.

1. Intent​

What problem does this system solve? One paragraph. Be specific about what the robot does and why.

Bad intent: "Create a robot controller" Good intent: "Build a multi-node ROS 2 system that navigates a turtlesim turtle to goal positions, reports its status continuously, and gracefully handles obstacle warnings from a mock sensor."

Why is the second better? It's concrete:

  • What's the scope? Multi-node, ROS 2
  • What's the goal? Navigate to positions
  • What data flows? Status reports, obstacle warnings
  • What's the graceful handling? Doesn't crash, continues operating

2. System Architecture​

How many nodes? What does each do? List them like:

Navigator Node
Input: Goal position (x, y, theta) via service request
Output: Velocity commands to turtle
Purpose: Accepts navigation goals, computes paths, issues movement commands

Status Monitor Node
Input: Current turtle state (from topics, odometry simulators)
Output: Robot status (position, velocity, battery) published every 100ms
Purpose: Aggregates state information, publishes to external subscribers

Obstacle Detector Node
Input: (None—generates mock sensor data)
Output: Obstacle warnings on topic
Purpose: Simulates obstacle detection, publishes warnings for Navigator to handle

Each node has input, output, and purpose. No mystery. No ambiguity.

3. Interfaces (Topics & Services)​

What's the contract between nodes? Define every topic and service:

Service: /navigate_to
Request: x (float), y (float), theta (float)
Response: success (bool), time_taken (float)
Purpose: Accept navigation goal, return completion status and time

Topic: /robot/status (custom TurtleStatus message)
Message fields: x (float), y (float), theta (float), vel_x (float), vel_y (float), battery (float)
Frequency: 10 Hz (every 100ms)
Subscribers: Status monitor, or external monitoring nodes
Purpose: Publish robot state continuously

Topic: /obstacles (sensor_msgs/LaserScan mock)
Message fields: angle_min, angle_max, distances (array)
Frequency: 5 Hz
Publishers: Obstacle detector
Purpose: Simulated obstacle data for Navigator to process

Why this detail? When implementing, the developer reads this and knows:

  • Exactly what message types to use
  • How often data flows
  • Who publishes, who subscribes
  • What fields go in custom messages

4. Success Criteria​

How do you know it worked? Measurable, testable conditions:

✅ Turtle reaches goal position within 2 seconds of service call
✅ Status messages published every 100ms (±10ms tolerance)
✅ System continues operating when 3+ obstacles detected (no crash, no freeze)
✅ Launch file with `ros2 launch` starts all nodes with correct parameters
✅ Navigator node runs without errors for 5+ minutes
✅ Service responds with completion time within 0.1s of actual movement time

Why measurable? You'll test each one explicitly in Lesson 7.3.

5. Non-Goals​

What's NOT in scope? Explicitly excluding these prevents scope creep:

❌ Real obstacle avoidance (only detection, no path planning around obstacles)
❌ Real LIDAR simulation (mock sensor only, not full physics)
❌ Multiple turtles (single turtle only)
❌ URDF or robot description (deferred to Module 2)
❌ Real hardware deployment (simulation only)
❌ Visual path visualization (logging/debugging only)

Writing "what's NOT included" is as important as writing "what IS included."


Your Specification Template​

Now you fill it in. Use this template:

# Turtle Robot Controller Specification

## Intent
[1 paragraph describing what this system does, concretely]

## System Architecture

### Navigator Node
Input: [What does it receive?]
Output: [What does it produce?]
Purpose: [Why does it exist?]

### Status Monitor Node
Input: [What does it receive?]
Output: [What does it produce?]
Purpose: [Why does it exist?]

### Obstacle Detector Node
Input: [What does it receive?]
Output: [What does it produce?]
Purpose: [Why does it exist?]

## Interfaces

### Service: /navigate_to
Request: [Fields]
Response: [Fields]
Purpose: [Why this service?]

### Topic: /robot/status
Message Type: [Custom or standard?]
Fields: [List each field]
Frequency: [Hz or ms?]
Purpose: [Why this topic?]

### Topic: /obstacles
Message Type: [Custom or standard?]
Fields: [List each field]
Frequency: [Hz or ms?]
Purpose: [Why this topic?]

## Success Criteria

✅ [Specific, measurable criterion 1]
✅ [Specific, measurable criterion 2]
✅ [Specific, measurable criterion 3]
✅ [Specific, measurable criterion 4]
✅ [Specific, measurable criterion 5]

## Non-Goals

❌ [What's NOT in scope 1]
❌ [What's NOT in scope 2]
❌ [What's NOT in scope 3]

What Makes a Specification GOOD?​

Test It Against These Criteria​

Criterion 1: Clarity

  • Could a developer who hasn't met you implement this from your spec alone?
  • No hand-waving ("intelligently handles obstacles") — be specific
  • No vague terms ("optimal path") — define exactly what you mean

Criterion 2: Completeness

  • Every topic has a message type defined
  • Every service has request/response types defined
  • Every node has inputs and outputs
  • Nothing left for someone to guess about

Criterion 3: Testability

  • Every success criterion is measurable
  • You can test it with ros2 topic echo or service calls
  • You can write a test script that validates each criterion

Criterion 4: Realism

  • Is the spec achievable in 90 minutes?
  • Are the success criteria reasonable?
  • Does it stretch your skills without breaking them?

Common Spec Mistakes to Avoid​

Mistake 1: Vague Success Criteria​

Bad: "Turtle navigates to goal" Good: "Turtle reaches goal position within 2 seconds, with position error < 0.1m"

Why? The first one is ambiguous. What counts as "reached"? The second is testable.

Mistake 2: Missing Node Responsibilities​

Bad: "System controls turtle" Good: "Navigator node computes velocity commands; Status Monitor publishes state; Obstacle Detector publishes warnings"

Why? The bad version doesn't clarify who does what. The good version makes clear separation of concerns.

Mistake 3: No Message Types​

Bad: "Nodes communicate via topics" Good: "Status Monitor publishes TurtleStatus (custom message with x, y, theta, vel_x, vel_y, battery fields) at 10 Hz"

Why? Without message types, the implementer has to invent them. With types, implementation is straightforward.

Mistake 4: Unrealistic Time Constraints​

Bad: "Turtle reaches goal in 0.1 seconds" Good: "Turtle reaches goal in 2 seconds" (realistic for turtlesim movement)

Why? If your spec is impossible, implementation fails. Make success criteria achievable.


The Turtle Specification Example (Reference)​

Here's what a completed specification looks like:

# Turtle Robot Controller Specification

## Intent
Build a multi-node ROS 2 system that controls a turtlesim turtle to achieve
autonomous navigation goals. The system accepts goal positions via service call,
publishes continuous status updates, and gracefully handles simulated obstacle
warnings without crashing or losing control.

## System Architecture

### Navigator Node
Input: Goal position (x, y, theta) via /navigate_to service request
Output: Velocity commands (cmd_vel) to turtle; Goal completion response
Purpose: Orchestrates movement toward goal. Accepts new goals via service.
Computes velocity commands based on goal. Returns success/time when done.

### Status Monitor Node
Input: Turtle odometry (pose, velocity) — either from /turtle1/pose topic
or computed from cmd_vel/odom if available
Output: /robot/status topic (custom TurtleStatus message)
Purpose: Continuously publishes robot state (position, velocity, battery) for
external monitoring. Enables other nodes to react to state changes.

### Obstacle Detector Node
Input: (None—generates simulated data)
Output: /obstacles topic (sensor_msgs/LaserScan mock structure)
Purpose: Simulates obstacle detection. Publishes periodic "detections" that
Navigator can handle. Tests system robustness.

## Interfaces

### Service: /navigate_to
Request:
- x (float): Goal X position in turtle coordinate system
- y (float): Goal Y position in turtle coordinate system
- theta (float): Goal orientation in degrees (0-360)
Response:
- success (bool): True if goal reached, false if aborted
- time_taken (float): Seconds elapsed from request to completion
Purpose: Primary command interface. Clients request navigation to position.
Navigator handles the goal and returns status.

### Topic: /robot/status
Message Type: TurtleStatus (custom)
Fields:
- x (float): Current X position
- y (float): Current Y position
- theta (float): Current orientation (degrees)
- vel_x (float): Velocity in X direction
- vel_y (float): Velocity in Y direction
- battery (float): Simulated battery level (0-100%)
Frequency: 10 Hz (every 100ms)
Subscribers: Status monitor dashboard, external decision systems
Purpose: Real-time state stream. Enables reactive behavior and monitoring.

### Topic: /obstacles
Message Type: sensor_msgs/LaserScan (simplified mock)
Fields:
- angle_min, angle_max: Detection angle range
- ranges: Array of distance measurements (simulated)
Frequency: 5 Hz (every 200ms)
Publishers: Obstacle Detector node
Purpose: Mock sensor data. Navigator subscribes and avoids/stops if obstacle
detected. Tests handling of sensor input.

## Success Criteria

✅ Service /navigate_to accepts goal and returns success=true when turtle reaches position within 0.2m
✅ Turtle moves to goal within 2 seconds from service request
✅ Status topic publishes TurtleStatus message every 100ms (±10ms variance acceptable)
✅ System receives and logs 10+ obstacle messages without crashing
✅ Launch file ros2 launch robot_controller start_system.launch.py starts all nodes and parameters
✅ Navigator node runs continuously for 5+ minutes without errors
✅ Custom TurtleStatus message compiles and serializes correctly

## Non-Goals

❌ Real obstacle avoidance (system detects obstacles but doesn't plan around them)
❌ Realistic LIDAR simulation (mock sensor only, not physics-based)
❌ Multiple turtles or coordination between agents
❌ Robot URDF or kinematics (direct velocity commands only)
❌ Real hardware deployment (turtlesim simulation only)
❌ Path planning or trajectory optimization (straight-line movement is acceptable)
❌ Visual RViz visualization (CLI validation only)

System Architecture Diagram​

Here's how the nodes interact:

┌─────────────────────────────────────────────────────┐
│ Turtle Robot Controller System │
├─────────────────────────────────────────────────────┤
│ │
│ Client App │
│ │ │
│ │ (service call: /navigate_to) │
│ ↓ │
│ ┌──────────────────────────────────────────┐ │
│ │ Navigator Node │ │
│ │ ├─ Input: Goal (x,y,theta) via service │ │
│ │ ├─ Computes: velocity commands │ │
│ │ └─ Output: cmd_vel to turtlesim │ │
│ └──────────────────────────────────────────┘ │
│ │ (cmd_vel) │ (/navigate_to response) │
│ │ └────────────► Client │
│ ↓ │
│ [TurtleSim Turtle]◄────────────────────────────┐ │
│ │ (updated pose) │ │
│ ↓ │ │
│ ┌──────────────────────────────────────────┐ │ │
│ │ Status Monitor Node │ │ │
│ │ ├─ Input: turtle pose/odometry │ │ │
│ │ ├─ Aggregates: position, velocity, battery
│ │ └─ Output: /robot/status (10 Hz) │───┤ │
│ └──────────────────────────────────────────┘ │ │
│ │ │
│ ┌──────────────────────────────────────────┐ │ │
│ │ Obstacle Detector Node │ │ │
│ │ ├─ Input: (generated simulated data) │ │ │
│ │ └─ Output: /obstacles (5 Hz) ───────────┼───┴──→ Navigator
│ └──────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘

Try With AI​

Setup: You'll use a chat AI (Claude, ChatGPT, or GitHub Copilot) to help refine your specification.

Phase 1: Draft Your Specification

First, write your rough specification using the template above. You can fill it with:

  • Concrete details (real node names, real message types like sensor_msgs/LaserScan)
  • Or high-level ideas (you can refine in phase 2)

Phase 2: AI Refinement Prompts

Once you have a draft, use these prompts with your AI:

Prompt 1: Clarity Check

I've written this ROS 2 specification for a turtle controller:

[paste your spec]

Are there any parts that are vague or ambiguous?
Where would a developer be confused implementing this?
What details are missing?

Prompt 2: Completeness Check

Looking at my specification, did I define:
- All message types (what fields, what types?)
- All topics (who publishes, who subscribes, at what frequency?)
- All services (what request/response structure?)
- All node responsibilities (what does each node do?)

Where are the gaps?

Prompt 3: Testability Check

Can each of these success criteria be tested with ROS 2 CLI tools?

[paste your success criteria]

Which ones are testable? Which ones are too vague to test?
How would I write a test for each one?

Expected Outcome: Your refined specification should be clear enough that:

  • A developer could implement it without asking questions
  • You could test each success criterion with concrete ROS 2 commands
  • You have no ambiguous terms (no "intelligently", "optimally", "well")

Safety Note: Your AI will sometimes suggest overly complex specs (adding features beyond the module scope). Remember: Non-Goals exclude URDF, Actions, tf2, and real obstacle avoidance. Keep it simple—focus on pub/sub, services, parameters, and launch files from Chapters 4-6.

Optional Stretch: Write your specification in PlantUML or Mermaid diagram format showing node communication. This forces you to think visually about system architecture.


Next Step: Lesson 7.2: Building the Controller →