pub mod acceleration;
pub mod delta_time;
pub mod ee_force;
pub mod environment;
pub mod exclusion_zones;
pub mod foot_clearance;
pub mod force_rate;
pub mod friction_cone;
pub mod grasp_force;
pub mod ground_reaction;
pub mod heading_rate;
pub mod iso15066;
pub mod joint_limits;
pub mod locomotion_velocity;
pub mod payload;
pub mod proximity;
pub mod self_collision;
pub mod stability;
pub mod step_length;
pub mod torque;
pub mod velocity;
pub mod workspace;
#[cfg(test)]
mod tests;
use crate::models::command::{Command, EndEffectorForce, JointState};
use crate::models::profile::{ExclusionZone, RobotProfile, WorkspaceBounds};
use crate::models::verdict::CheckResult;
pub fn run_all_checks(
command: &Command,
profile: &RobotProfile,
previous_joints: Option<&[JointState]>,
) -> Vec<CheckResult> {
if command.joint_states.is_empty() && !profile.joints.is_empty() {
let fail = CheckResult {
name: "empty_joint_states".to_string(),
category: "physics".to_string(),
passed: false,
details: "command contains no joint states but profile defines joints".to_string(),
};
return vec![fail; 10];
}
let margins = profile.real_world_margins.as_ref();
let envelope = profile.task_envelope.as_ref();
let effective_velocity_scale = match envelope.and_then(|e| e.global_velocity_scale) {
Some(env_scale) => env_scale.min(profile.global_velocity_scale),
None => profile.global_velocity_scale,
};
let effective_workspace: &WorkspaceBounds = match envelope.and_then(|e| e.workspace.as_ref()) {
Some(ws) => ws,
None => &profile.workspace,
};
let mut effective_zones: Vec<ExclusionZone> = profile.exclusion_zones.clone();
if let Some(env) = envelope {
effective_zones.extend(env.additional_exclusion_zones.iter().cloned());
}
let mut results = vec![
joint_limits::check_joint_limits(&command.joint_states, &profile.joints, margins),
velocity::check_velocity_limits(
&command.joint_states,
&profile.joints,
effective_velocity_scale,
margins,
),
torque::check_torque_limits(&command.joint_states, &profile.joints, margins),
acceleration::check_acceleration_limits(
&command.joint_states,
previous_joints,
&profile.joints,
command.delta_time,
margins,
),
workspace::check_workspace_bounds(&command.end_effector_positions, effective_workspace),
exclusion_zones::check_exclusion_zones(
&command.end_effector_positions,
&effective_zones,
&command.zone_overrides,
),
self_collision::check_self_collision(
&command.end_effector_positions,
&profile.collision_pairs,
profile.min_collision_distance,
),
delta_time::check_delta_time(command.delta_time, profile.max_delta_time),
stability::check_stability(command.center_of_mass.as_ref(), profile.stability.as_ref()),
proximity::check_proximity_velocity(
&command.joint_states,
&profile.joints,
&command.end_effector_positions,
&profile.proximity_zones,
effective_velocity_scale,
),
];
let mut loco_results = run_locomotion_checks(command, profile);
results.append(&mut loco_results);
let mut manip_results = run_manipulation_checks(command, profile, None);
results.append(&mut manip_results);
results.push(iso15066::check_iso15066_force_limits(
&command.end_effector_positions,
&command.end_effector_forces,
&profile.proximity_zones,
None, ));
let mut env_results = run_environment_checks(command, profile);
results.append(&mut env_results);
results
}
pub fn run_manipulation_checks(
command: &Command,
profile: &RobotProfile,
previous_forces: Option<&[EndEffectorForce]>,
) -> Vec<CheckResult> {
if profile.end_effectors.is_empty() {
return vec![];
}
vec![
ee_force::check_ee_force_limits(&command.end_effector_forces, &profile.end_effectors),
grasp_force::check_grasp_force_limits(&command.end_effector_forces, &profile.end_effectors),
force_rate::check_force_rate_limits(
&command.end_effector_forces,
previous_forces,
&profile.end_effectors,
command.delta_time,
),
payload::check_payload_limits(
&command.end_effector_forces,
command.estimated_payload_kg,
&profile.end_effectors,
),
]
}
pub fn run_locomotion_checks(command: &Command, profile: &RobotProfile) -> Vec<CheckResult> {
let (loco, config) = match (&command.locomotion_state, &profile.locomotion) {
(Some(l), Some(c)) => (l, c),
_ => return vec![],
};
vec![
locomotion_velocity::check_locomotion_velocity(loco, config),
foot_clearance::check_foot_clearance(loco, config),
ground_reaction::check_ground_reaction(loco, config),
friction_cone::check_friction_cone(loco, config),
step_length::check_step_length(loco, config),
heading_rate::check_heading_rate(loco, config),
]
}
pub fn run_environment_checks(command: &Command, profile: &RobotProfile) -> Vec<CheckResult> {
let Some(env) = &command.environment_state else {
return vec![];
};
let mut results = Vec::new();
results.push(environment::check_emergency_stop(env));
if let Some(config) = &profile.environment {
results.push(environment::check_terrain_incline(env, config));
results.push(environment::check_actuator_temperature(env, config));
results.push(environment::check_battery_state(env, config));
results.push(environment::check_communication_latency(env, config));
}
results
}