| name | test-in-simulation |
| description | Test modules in Isaac Sim simulation environment end-to-end. Use after implementing and integrating a module to verify functionality. Covers test scenarios, monitoring, recording, and analysis of simulation tests. |
| license | Apache-2.0 |
| metadata | {"author":"AirLab CMU","repository":"AirStack"} |
Skill: Test Module in Simulation
When to Use
After implementing and integrating a module, test it in the full Isaac Sim simulation environment to verify end-to-end functionality.
Prerequisites
- Module built and integrated into autonomy stack
- Isaac Sim container accessible
- Understanding of expected module behavior
- Test scenario planned
Testing Strategy
- Unit tests: Verify module logic in isolation (covered in module development)
- Integration tests: Test module with mock inputs
- Simulation tests: Full autonomy stack in Isaac Sim (this skill)
- Hardware tests: Deploy to real robot (separate workflow)
This skill focuses on simulation testing.
Steps
1. Prepare Test Environment
Ensure containers are ready:
airstack status
airstack up isaac-sim robot
ISAAC_SIM_SCRIPT_NAME="example_one_px4_pegasus_launch_script.py" airstack up isaac-sim robot
2. Verify Module is Launched
Check that your module is running in the autonomy stack:
docker exec airstack-robot-desktop-1 bash -c "ros2 node list | grep your_module"
docker exec airstack-robot-desktop-1 bash -c "ros2 node info /drone1/namespace/your_node"
3. Monitor Key Topics
Set up topic monitoring to verify data flow:
docker exec airstack-robot-desktop-1 bash -c "ros2 topic hz /drone1/odometry"
docker exec airstack-robot-desktop-1 bash -c "ros2 topic hz /drone1/global_plan"
docker exec airstack-robot-desktop-1 bash -c "ros2 topic hz /drone1/trajectory_controller/trajectory_segment_to_add"
docker exec airstack-robot-desktop-1 bash -c "ros2 topic hz /drone1/odometry /drone1/trajectory_controller/trajectory_segment_to_add"
4. Visualize in Ground Control Station
If GCS is running, use it for visualization:
airstack up gcs
In GCS:
- View drone telemetry
- Monitor autonomy status
- Send waypoints
- Visualize trajectories
5. Use RViz for Detailed Visualization
RViz provides detailed topic visualization:
RViz configuration:
- Add → By topic → Select topics
- Fixed Frame:
map or world
- Save configuration for reuse
6. Design Test Scenario
Plan specific tests for your module:
For Local Planners:
- Obstacle avoidance: Spawn obstacles, verify path goes around
- Goal reaching: Set waypoint, verify convergence
- Dynamic obstacles: Moving obstacles, verify reactive behavior
- Edge cases: Narrow passages, dead ends
For Global Planners:
- Path generation: Set distant goal, verify feasible path
- Replanning: Block path, verify replanning
- Multi-waypoint: Multiple waypoints, verify order
For Controllers:
- Tracking accuracy: Follow trajectory, measure error
- Stability: Aggressive maneuvers, verify stability
- Disturbance rejection: Apply external forces in sim
For Perception:
- Accuracy: Compare estimates with ground truth
- Latency: Measure processing time
- Robustness: Various lighting, textures
7. Execute Test Scenario
Method 1: Manual Commands via Behavior Tree GUI
Method 2: Publish Test Commands
docker exec airstack-robot-desktop-1 bash -c "ros2 topic pub --once /drone1/global_plan nav_msgs/Path '
header:
frame_id: \"map\"
poses:
- pose:
position: {x: 5.0, y: 0.0, z: 2.0}
orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
- pose:
position: {x: 10.0, y: 5.0, z: 2.0}
orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
'"
docker exec airstack-robot-desktop-1 bash -c "ros2 service call /drone1/your_module/trigger std_srvs/Trigger"
Method 3: Scripted Test Sequence
Create a test script:
File: scripts/test_your_module.py
import rclpy
from rclpy.node import Node
from nav_msgs.msg import Path
from geometry_msgs.msg import PoseStamped
import time
class ModuleTester(Node):
def __init__(self):
super().__init__('module_tester')
self.plan_pub = self.create_publisher(Path, '/drone1/global_plan', 10)
time.sleep(1)
def test_scenario_1(self):
"""Test basic waypoint following"""
self.get_logger().info("Running test scenario 1...")
path = Path()
path.header.frame_id = "map"
path.header.stamp = self.get_clock().now().to_msg()
for x, y, z in [(5, 0, 2), (10, 5, 2), (10, 10, 2)]:
pose = PoseStamped()
pose.header.frame_id = "map"
pose.pose.position.x = float(x)
pose.pose.position.y = float(y)
pose.pose.position.z = float(z)
pose.pose.orientation.w = 1.0
path.poses.append(pose)
self.plan_pub.publish(path)
self.get_logger().info("Published test path")
def main():
rclpy.init()
tester = ModuleTester()
tester.test_scenario_1()
rclpy.spin(tester)
tester.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Run test:
docker exec airstack-robot-desktop-1 bash -c "sws && python3 scripts/test_your_module.py"
8. Record Test Data
Record ROS bag for later analysis:
docker exec airstack-robot-desktop-1 bash -c "ros2 bag record -a -o /tmp/test_run_1"
docker exec airstack-robot-desktop-1 bash -c "ros2 bag record \
/drone1/odometry \
/drone1/global_plan \
/drone1/trajectory_controller/trajectory_segment_to_add \
/drone1/your_module/debug \
-o /tmp/test_run_1"
docker cp airstack-robot-desktop-1:/tmp/test_run_1 ./test_data/
9. Analyze Test Results
Check Topic Data
ros2 bag play test_data/test_run_1
ros2 bag info test_data/test_run_1
ros2 bag play test_data/test_run_1 --topics /drone1/odometry | tee odom_data.txt
Compute Metrics
Create analysis script:
import rclpy
from rclpy.node import Node
from nav_msgs.msg import Odometry, Path
import numpy as np
class TestAnalyzer(Node):
def __init__(self):
super().__init__('test_analyzer')
self.odom_positions = []
self.planned_positions = []
self.odom_sub = self.create_subscription(
Odometry, '/drone1/odometry', self.odom_callback, 10)
self.plan_sub = self.create_subscription(
Path, '/drone1/global_plan', self.plan_callback, 10)
def odom_callback(self, msg):
pos = msg.pose.pose.position
self.odom_positions.append([pos.x, pos.y, pos.z])
def plan_callback(self, msg):
self.planned_positions = [[p.pose.position.x,
p.pose.position.y,
p.pose.position.z] for p in msg.poses]
def compute_metrics(self):
if not self.odom_positions or not self.planned_positions:
self.get_logger().warn("Insufficient data")
return
self.get_logger().info(f"Mean tracking error: {error_mean:.3f} m")
Visual Analysis
Plot trajectories:
import matplotlib.pyplot as plt
plt.figure()
plt.plot(actual_x, actual_y, label='Actual')
plt.plot(planned_x, planned_y, label='Planned', linestyle='--')
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.legend()
plt.grid(True)
plt.savefig('trajectory_comparison.png')
10. Verify Expected Behavior
Create a checklist for your module:
For Local Planner:
For Global Planner:
For Controller:
11. Test Edge Cases
Don't just test the happy path:
12. Multi-Robot Testing (if applicable)
If module supports multi-robot:
NUM_ROBOTS=2 airstack up isaac-sim robot
docker exec airstack-robot-desktop-1 bash -c "ros2 node list | grep robot"
13. Performance Profiling
Monitor system resources:
docker stats airstack-robot-desktop-1
docker exec airstack-robot-desktop-1 bash -c "top -b -n 1 | grep ros"
docker exec airstack-robot-desktop-1 bash -c "perf record -g ros2 run your_package your_node"
14. Document Test Results
Create test report:
File: test_reports/your_module_test_YYYYMMDD.md
# Test Report: Your Module
## Test Date
YYYY-MM-DD
## Test Environment
- Isaac Sim version: X.Y.Z
- AirStack version: X.Y.Z
- Docker image: airstack:tag
- Scene: example_one_px4_pegasus_launch_script.py
## Test Scenarios
### Scenario 1: Basic Waypoint Following
**Description:** Single waypoint navigation
**Expected:** Drone reaches waypoint within 0.5m
**Result:** ✓ PASS
- Final error: 0.23m
- Time to goal: 15.3s
**Data:** test_data/scenario_1.bag
### Scenario 2: Obstacle Avoidance
**Description:** Navigate around static obstacle
**Expected:** Path avoids obstacle with >1m clearance
**Result:** ✗ FAIL
- Minimum clearance: 0.4m (below threshold)
- Issue: Cost map underestimated obstacle size
**Action:** Increase expansion radius in config
## Performance Metrics
- Average CPU: 15%
- Average latency: 45ms
- Publish rate: 10 Hz (as expected)
## Issues Found
1. Issue description
- Reproduction steps
- Proposed fix
## Conclusion
Summary of test results and next steps.
Automated Testing
For CI/CD, create automated test scripts:
#!/bin/bash
set -e
docker-compose up -d isaac-sim robot
sleep 30
docker exec airstack-robot-desktop-1 bash -c "sws && python3 scripts/test_scenario_1.py"
docker exec airstack-robot-desktop-1 bash -c "sws && python3 scripts/test_scenario_2.py"
if [ -f "/tmp/test_results_pass" ]; then
echo "Tests PASSED"
exit 0
else
echo "Tests FAILED"
exit 1
fi
Common Issues
Simulation Issues
- ❌ Isaac Sim not responding
- ✅ Check GPU availability, restart container
- ❌ PX4 not connecting
- ✅ Check MAVLink ports, verify PX4 processes
- ❌ Drone not moving
- ✅ Check arm/offboard commands, verify mode
Integration Issues
- ❌ Module not receiving data in sim
- ✅ Check topic remapping, verify sim publishes topics
- ❌ Commands not reaching PX4
- ✅ Verify control chain: planner → controller → mavros → PX4
Performance Issues
- ❌ Slow simulation
- ✅ Reduce sensor resolution, decrease update rates
- ❌ High latency
- ✅ Profile module, optimize algorithm
Tips for Effective Testing
- Start simple: Test basic functionality before complex scenarios
- One change at a time: Isolate what you're testing
- Use visualization: RViz/GCS help identify issues quickly
- Record everything: Bags are invaluable for debugging
- Automate: Write scripts for repeatable tests
- Document: Record what you tested and results
References
-
ROS 2 Testing:
-
Isaac Sim:
-
AirStack:
-
Related Skills: