name: simulation-code-validation version: 1.0.0 category: robotics-technical description: Encodes validation patterns for robotics simulation code (ROS 2, Gazebo, Isaac Sim). Ensures code examples are testable, safe, and follow simulation-first pedagogy. Validates Python syntax, ROS 2 patterns, URDF/SDF markup, and troubleshooting completeness. activation_trigger: "When validating robotics code examples, checking simulation compatibility, or ensuring pedagogical safety in lessons"
Simulation Code Validation Skill
Skill Identity
You possess deep knowledge of robotics simulation validation, code quality assurance, and pedagogical safety. Use this skill to:
- Validate robotics code against simulation environments (Turtlesim, Gazebo, Isaac Sim, MuJoCo)
- Catch common errors before they reach students (syntax, imports, ROS 2 patterns)
- Ensure pedagogical safety (no forward references, CEFR-appropriate, expected outputs shown)
- Validate markup (URDF/SDF XML for Gazebo, custom message definitions)
- Audit troubleshooting completeness (all common errors documented with solutions)
Core Knowledge: Code Validation Frameworks
Layer 1: Static Syntax Validation
Python Validation Checklist:
- Valid Python 3.8+ syntax (not Python 2)
- All imports exist and are correct:
import rclpy✅from rclpy.node import Node✅- Message imports:
from std_msgs.msg import String✅ - Geometry imports:
from geometry_msgs.msg import Twist✅
- No undefined variables or undefined function references
- String formatting uses f-strings (modern, readable)
- Indentation consistent (4 spaces, no tabs)
- No missing colons or parentheses
- Main guard:
if __name__ == '__main__': - Type hints present on public methods (optional but recommended)
PEP 8 Compliance:
- Line length ≤ 88 characters (Black formatter standard)
- Function names snake_case
- Class names PascalCase
- Constants UPPER_SNAKE_CASE
- 2 blank lines between classes
- 1 blank line between methods
Example Validation:
# ❌ BAD - undefined variable
def publisher_callback(self):
msg = String()
msg.data = message_text # 'message_text' not defined
# ✅ GOOD - variable defined
def publisher_callback(self):
message_text = "Hello"
msg = String()
msg.data = message_text
Layer 2: ROS 2 Pattern Validation
Publisher Validation Checklist:
-
rclpy.init(args=args)called exactly ONCE (before node creation) - Node has unique, descriptive name:
Node('my_publisher') - Publisher created with 3 params:
create_publisher(MessageType, '/topic/name', queue_size) - Topic name follows convention: starts with
/, uses lowercase, hyphens or underscores - Message type imported correctly:
from X.msg import Y - Timer or callback exists (node must do something)
-
rclpy.spin(node)present (without this, callbacks never fire) -
rclpy.shutdown()on exit or in finally block - Expected output documented (what should student see?)
Subscriber Validation Checklist:
-
rclpy.init()called once - Subscription created:
create_subscription(MsgType, '/topic', callback, queue_size) - Topic name matches publisher exactly (case-sensitive!)
- Message type matches publisher exactly
- Callback function exists with correct signature:
def callback(self, msg): - Message fields accessed correctly (e.g.,
msg.data,msg.x) -
rclpy.spin()present - Logging present for debugging:
self.get_logger().info()
Multi-Node System Validation:
- Each node has unique name
- All topic names consistent across nodes
- All message types match between pub/sub pairs
- No circular dependencies (node A waits for B waits for A)
- Instructions show how to run multiple terminals
- Expected output shows all nodes running independently
-
ros2 node listcommand shown (proves nodes exist) -
ros2 topic listcommand shown (proves topics created)
Common ROS 2 Errors to Catch:
| Error | Cause | Fix |
|---|---|---|
rclpy.init() called twice |
Multiple nodes in same process init twice | Call rclpy.init() once, before all nodes |
| Topic not publishing | Publisher not spinning, or topic name wrong | Check topic with ros2 topic list |
| Callback never fires | Subscriber not spinning, or message type mismatch | Verify rclpy.spin() and types match |
| ModuleNotFoundError: rclpy | ROS 2 not installed | sudo apt install ros-humble-rclpy |
| ModuleNotFoundError: geometry_msgs | geometry_msgs not installed | sudo apt install ros-humble-geometry-msgs |
Layer 3: Gazebo Simulation Validation
URDF Syntax Validation:
- Valid XML (all tags closed, valid UTF-8)
- Root element:
<robot name="robot_name"> - All links have mass > 0 (or fixed_base in collision)
- All joints connect valid link pairs (no dangling references)
- Inertia matrices valid (principal moments satisfy triangle inequality)
- Visual and collision geometry defined
- No circular joint chains (unless intentional)
SDF Syntax Validation (Gazebo 11+):
- Valid XML with
<sdf version="1.9"> - Model name specified
- All links have
<inertial>blocks - Physics engine specified (
<physics type="ode">orbullet) - Gravity defined (typically
0 0 -9.81)
Gazebo-Specific Errors:
| Error | Cause | Fix |
|---|---|---|
| Model doesn't appear in Gazebo | Model file not found, or path incorrect | Check path in launch file, verify URDF exists |
| Model falls through ground | Inertia too light or collision undefined | Add mass, define collision geometry |
| Joint doesn't move | Joint limit reached, or controller not connected | Check joint limits, verify Gazebo controller plugin |
| Physics unstable (jittering) | Timestep too large, inertia ratios bad | Reduce step size in physics tag |
Layer 4: Isaac Sim Validation
Isaac Sim Scene Validation:
- USD file format valid (Pixar Universal Scene Description)
- Physics enabled on rigid bodies
- Joints have appropriate drive strengths (not too high)
- Sensors have correct reference frames
- Cameras have valid intrinsics (focal length, resolution)
- Lidar scan distance matches expected range
Common Isaac Sim Issues:
- Model imports but doesn't appear → Check asset path and load callbacks
- Physics too fast/slow → Adjust substeps and step size in PhysicsScene
- Sensors return wrong data → Verify sensor attachment frames and enable flags
- Synthetic data generation fails → Check camera paths and renderer settings
Pedagogical Safety Validation
Anti-Forward-Reference Check
Forward reference = mentioning a concept not yet taught
Example Forward Reference ❌:
"In Lesson 2, we'll create a publisher node to send motion commands via ROS 2 topics. Next lesson, we'll add machine learning vision processing to detect obstacles."
Problem: Student in Lesson 2 thinks they need to know ML to understand publishers. Breaks confidence.
Fixed ✅:
"In Lesson 2, we'll create a publisher node to send motion commands via ROS 2 topics. Publishers are the foundation for all ROS 2 communication."
Check: Does lesson 2 explain "what is machine learning"? No → Don't mention it.
Validation Steps:
- Extract all concepts mentioned in the code examples
- Extract all concepts in explanatory text
- Check against lesson
conceptsin YAML frontmatter - Flag any concept not in that lesson or earlier lessons
- Verify all concept counts stay within CEFR limits
Expected Output Validation
Every code example MUST have expected output shown.
Template:
# Code example
print("Hello, World!")
Expected Output (REQUIRED):
Hello, World!
Validation:
- Expected output shown (as code block or screenshot)
- Output is realistic (not hallucinated)
- Output was verified (by actually running code)
- Output shows what student will see (exact terminal output)
Troubleshooting Completeness Audit
For each code example, audit troubleshooting:
- "Command not found" errors documented (if CLI command)
- Import errors documented (if Python code)
- Common parameter mistakes documented
- Timeout/connection issues documented
- Expected vs actual output comparison provided
- "Why might this happen?" explained (not just "how to fix")
- At least 3 common mistakes documented per example
Example Audit:
# Lesson code:
ros2 run turtlesim turtlesim_node
Troubleshooting audit:
- "Command not found" → ROS 2 not installed
- "Could not find executable" → turtlesim package missing
- Window won't open → Display server issue (SSH without X forwarding)
- "Connection refused" → ROS_DOMAIN_ID mismatch
---
## Code Validation Workflows
### Workflow 1: Validate a Single Code Example
**Input**: Python file or code snippet
**Steps**:
1. **Syntax Check**: Run Python syntax validator
- `python3 -m py_compile code.py`
- Catch: missing colons, undefined variables, invalid imports
2. **ROS 2 Pattern Check**: Verify against Layer 2 checklist
- Node structure valid?
- Publisher/subscriber patterns correct?
- Callbacks well-formed?
3. **Runtime Validation**: Mentally trace execution
- Does `rclpy.init()` happen before node creation?
- Does `rclpy.spin()` exist?
- Are message fields accessed correctly?
4. **Output Verification**: Check expected output section exists
- Is output realistic (tested manually)?
- Does it match what code would actually produce?
5. **Troubleshooting Audit**: Count error sections
- Minimum 3 common errors documented?
- Solutions provided for each?
**Output**: Pass/Fail with list of issues found
---
### Workflow 2: Validate Complete Lesson
**Input**: Lesson markdown file with YAML frontmatter and multiple code examples
**Steps**:
1. **Frontmatter Validation**:
- [ ] All required YAML fields present
- [ ] `simulation_required` specified (Turtlesim/Gazebo/Isaac)
- [ ] `safety_level` appropriate for CEFR level
- [ ] `cefr_level` specified (A2/B1/C2)
- [ ] `concepts` list matches content
- [ ] `learning_objectives` measurable and SMART
2. **Content Structure Validation**:
- [ ] Only ONE H1 heading (lesson title)
- [ ] Sections in order: Intro, Prerequisites, Content, Code, Troubleshooting, Self-Assessment, Next
- [ ] No subsection skipped
3. **Concept Density Check**:
- Count unique concepts taught
- A2: should be 5-7 concepts
- B1: should be 7-10 concepts
- C2: unlimited
- Flag if exceeds limit
4. **Forward Reference Check**:
- [ ] No future lesson concepts mentioned
- [ ] No advanced topics teased without context
- [ ] Stays focused on lesson objectives
5. **Code Example Validation**:
- [ ] Each code example has expected output
- [ ] Syntax is valid
- [ ] ROS 2 patterns correct
- [ ] Copy-pasteable (tested)
6. **Troubleshooting Completeness**:
- [ ] At least 3 common errors per major code block
- [ ] Solutions provided
- [ ] Expected vs actual output comparison
7. **Pedagogical Safety**:
- [ ] Three Roles framework demonstrated (💬 CoLearning prompts)
- [ ] No meta-commentary (no "Layer 2" labels visible)
- [ ] Self-assessment checklist present
- [ ] Next lesson linked
**Output**: Validation report with pass/fail for each section
---
## Validation Rules by Simulator
### Turtlesim Validation Rules
Turtlesim is **software-only, 2D graphics, no physics simulation**. It runs in a display window.
**Validation**:
- [ ] Code uses only standard ROS 2 messages (std_msgs, geometry_msgs)
- [ ] No physics assumptions (no gravity, friction, inertia)
- [ ] Coordinates are 2D (x, y, theta)
- [ ] Movement commands use `Twist` message type
- [ ] Turtle starting position documented (usually 5.5, 5.5)
- [ ] No collision detection expected
- [ ] Display/graphics required (note for SSH users)
**Common Turtlesim Errors**:
| Error | Cause | Fix |
|-------|-------|-----|
| Turtle doesn't move | Publisher not sending to `/turtle1/cmd_vel` | Check topic name exactly |
| No window appears | Display server not available (SSH) | Use `export DISPLAY=:0` or use X forwarding |
| `ros2 run turtlesim turtlesim_node` fails | turtlesim not installed | `sudo apt install ros-humble-turtlesim` |
| Topic `/turtle1/pose` not available | Turtlesim not running | Launch in separate terminal first |
---
### Gazebo Validation Rules
Gazebo includes **physics simulation, sensors (lidar/camera), complex robot models**.
**Validation**:
- [ ] URDF/SDF file valid XML with correct schema
- [ ] Robot model has defined mass and inertia
- [ ] Collision geometry defined
- [ ] Sensors have correct attachment frames
- [ ] Physics parameters realistic (gravity ~9.81 m/s², timestep 0.001 s)
- [ ] Launch file includes model spawning
- [ ] Joint controllers defined (if joints move)
- [ ] Expected output shows model loading and physics running
**Common Gazebo Errors**:
| Error | Cause | Fix |
|-------|-------|-----|
| Model doesn't appear | URDF parsing error or model file missing | Check `gazebo_ros` plugin, verify file paths |
| Model falls through ground | Collision geometry missing | Add `<collision>` block with valid geometry |
| Joint doesn't move | No controller plugin or joint limits exceeded | Add `gazebo_ros2_control` plugin, check limits |
| Simulation very slow | Timestep too small or physics too complex | Increase `max_step_size` in physics tag |
| Camera/Lidar returns no data | Sensor not attached or plugin missing | Verify sensor frames, add plugin in URDF |
---
### Isaac Sim Validation Rules
Isaac Sim includes **advanced physics, synthetic data generation, ML-ready assets**.
**Validation**:
- [ ] USD asset paths valid (correct directory structure)
- [ ] Physics enabled on rigid bodies
- [ ] Sensor ground truth available (if used for ML)
- [ ] ROS 2 bridge properly configured
- [ ] Synthetic data annotation enabled (if generating datasets)
- [ ] Lighting suitable for vision tasks
- [ ] GPU memory requirements documented
**Common Isaac Sim Errors**:
| Error | Cause | Fix |
|-------|-------|-----|
| Assets don't load | Incorrect USD path or asset not downloaded | Check `NVIDIA_NUCLEUS` path, verify asset exists |
| Physics glitchy | Substeps too low or inertia badly scaled | Increase `number_of_substeps` to 4+ |
| ROS 2 topics not appearing | Isaac ROS 2 bridge not loaded | Load `omni.isaac.ros2_bridge` extension |
| Synthetic data export fails | Annotation layer not set | Enable `omni.syntheticdata` and set annotator labels |
---
## Validation Checklist Template
Use this for auditing any robotics code lesson:
```markdown
## Code Validation Audit
### Python Syntax
- [ ] Valid Python 3.8+ syntax
- [ ] All imports correct and available
- [ ] No undefined variables
- [ ] PEP 8 compliant
- [ ] Main guard present
### ROS 2 Patterns
- [ ] rclpy.init() called exactly once
- [ ] Node has unique name
- [ ] Publishers/subscribers correct
- [ ] Topic names follow conventions
- [ ] Message types match
- [ ] Callbacks well-formed
- [ ] rclpy.spin() present
- [ ] rclpy.shutdown() present
### Simulation Environment
- [ ] Simulator specified (Turtlesim/Gazebo/Isaac)
- [ ] Expected output shown
- [ ] Output verified (not hallucinated)
- [ ] Copy-pasteable code
### Troubleshooting
- [ ] At least 3 common errors documented
- [ ] Solutions provided for each
- [ ] Expected vs actual output comparison
- [ ] Diagnostic commands shown
### Pedagogical Safety
- [ ] No forward references
- [ ] CEFR concept count OK
- [ ] Self-assessment present
- [ ] Three Roles framework shown (💬)
- [ ] Framework stays invisible
- [ ] Next lesson linked
Success Criteria
Code validated with this skill must meet:
- Zero Python syntax errors (verified by linter)
- Zero ROS 2 pattern violations (all imports, spin(), shutdown() present)
- All expected outputs documented and realistic
- Troubleshooting covers 90% of common errors
- No forward references to future concepts
- CEFR concept count within limits
- Copy-pasteable and tested before lesson release
- Simulator environment explicitly specified
- Safety checks for autonomous movement
- Self-assessment checklist included
- Three Roles framework present but invisible
- Markdown valid (no broken links, code blocks formatted correctly)