Adding a Fault Type
A fault type is one new behavior inside an existing injector. Add a fault type when the message stream is already supported, but you want to mutate it in a new way.
For example, odometry covariance inflation belongs in the existing odom injector because it still operates on nav_msgs/msg/Odometry.
1. Pick the Config Key
Choose a key that describes the parameter, not the implementation detail.
Good examples:
pose_covariance_scale
pose_covariance_floor
yaw_bias_deg
range_noise_stddev
Use units in the key when the unit is not obvious:
yaw_bias_deg
delay_ms
2. Add the Key to the Schema
Update fault_config_schema so the key is accepted for the correct injector type.
Example for odom:
const std::unordered_set<std::string> kOdomKeys = {
"drop_probability",
"delay_ms",
"pose_covariance_scale",
"pose_covariance_floor",
};
This keeps YAML validation, runtime config updates, and documentation aligned.
3. Add Value Validation
Update scenario_validator when the key has constraints.
Typical rules:
standard deviations must be non-negative
probabilities must be between
0.0and1.0covariance scale/floor values must be non-negative
enum-like strings should be checked against known values
For numeric non-negative keys, use the existing validator helper pattern:
validate_non_negative_number_key(fault, "pose_covariance_scale", result);
4. Implement the Mutation
Add a small method to the typed injector and call it from the message callback.
For odom covariance:
void OdomFaultInjector::apply_covariance_scale(nav_msgs::msg::Odometry& msg) {
const double pose_scale = active_max_double("pose_covariance_scale", 1.0);
const double pose_floor = active_max_double("pose_covariance_floor", 0.0);
if (pose_scale != 1.0 || pose_floor > 0.0) {
for (auto& value : msg.pose.covariance) {
value = std::max(value * pose_scale, pose_floor);
}
}
}
Use helpers from FaultInjectorBase where possible:
active_max_double(...)when the strongest active value should winactive_sum_double(...)when active faults should stack additivelyactive_max_int(...)for integer configurationshould_drop()for common message droppingactive_delay()for common message delay
5. Decide How Faults Combine
Be explicit about how multiple active faults interact.
Common patterns:
bias values stack additively
noise values can use max or sum depending on desired behavior
scale/floor values usually use max
drop_probability usually uses max
delay_ms usually uses max
Document the choice in a short code comment when it is not obvious.
6. Add YAML Examples
Add a focused example in config/ or extend multi_injector_faults.yaml.
Example:
- id: odom_covariance_inflation
injector_id: odom
active_on_startup: false
config:
pose_covariance_scale: 10.0
pose_covariance_floor: 0.05
twist_covariance_scale: 10.0
twist_covariance_floor: 0.05
7. Add Tests
Test the smallest behavior that proves the new fault works.
For a typed injector, prefer publishing a raw message and checking the output topic:
publish /odom_raw -> injector -> receive /odom
For schema and validation:
schema accepts the new key
validator rejects invalid values
service config updates accept the new key when appropriate
8. Update Documentation
Update:
README.mdfault key tablesexample YAML files
Doxygen comments if the public header changed
this guide if the process changed
Then regenerate docs:
cd /home/reece/fault_injection_ws
source /opt/ros/jazzy/setup.bash
colcon build --symlink-install --packages-select ros2_fault_injection --cmake-target generate_doxygen_api
Checklist
Config key added to
fault_config_schemaInvalid values rejected in
scenario_validatorTyped injector applies the fault
Callback calls the new mutation method
Example YAML added
README updated
Tests added or updated
Doxygen docs regenerate cleanly