/** * Shared safety gates: per-robot velocity limits, optional workspace * geofence, and fail-safe zero-Twist on transport loss. * * Adapters (MCP, OpenClaw, Gemini, teleop, skills) must call these * helpers rather than reading `config.safety` directly so a mixed * fleet does not share one clamp. */ import type { AgenticROSConfig, RobotSafetyOverlay, WorkspaceLimits } from "./config.js"; import type { ProfileRobot } from "./robot-profile.js"; import type { RosTransport } from "./transport/transport.js"; /** How many zero-Twist publishes `/estop` and `ros2_estop` send so the base reliably stops. */ export declare const ESTOP_PUBLISH_COUNT = 5; export declare const TWIST_MSG_TYPE = "geometry_msgs/msg/Twist"; export declare const ZERO_TWIST: { linear: { x: number; y: number; z: number; }; angular: { x: number; y: number; z: number; }; }; export interface SafetyLimits { maxLinearVelocity: number; maxAngularVelocity: number; workspaceLimits?: WorkspaceLimits; } export interface SafetyCheckResult { block: boolean; blockReason?: string; } export interface TwistComponents { linear: { x: number; y: number; z: number; }; angular: { x: number; y: number; z: number; }; } /** * Resolve velocity + workspace limits for a robot. Robot overlay fields * win; unset fields inherit the gateway `config.safety` defaults. */ export declare function resolveSafetyForRobot(config: AgenticROSConfig, robot?: { safety?: RobotSafetyOverlay; } | null): SafetyLimits; /** True when the payload looks like geometry_msgs/Twist. */ export declare function isTwistMessage(msg: unknown): boolean; export declare function checkTwistMessage(limits: SafetyLimits, msg: unknown): SafetyCheckResult; /** Scale a Twist down to the velocity ceilings (teleop / skills). */ export declare function clampTwistToLimits(limits: SafetyLimits, linearX: number, linearY: number, linearZ: number, angularX: number, angularY: number, angularZ: number): TwistComponents; export declare function checkWorkspacePosition(limits: SafetyLimits, x: number, y: number): SafetyCheckResult; /** * Pull map-frame (x, y) pairs from Twist-unrelated nav payloads: * `{x,y}`, Pose, PoseStamped, NavigateToPose goal, NavigateThroughPoses. */ export declare function extractWorkspacePositions(payload: unknown): Array<{ x: number; y: number; }>; export declare function checkWorkspacePayload(limits: SafetyLimits, payload: unknown): SafetyCheckResult; export declare function checkPublishSafety(config: AgenticROSConfig, params: Record, robot?: { safety?: RobotSafetyOverlay; } | null): SafetyCheckResult; export declare function checkActionGoalSafety(config: AgenticROSConfig, params: Record, robot?: { safety?: RobotSafetyOverlay; } | null): SafetyCheckResult; export declare function checkInputsWorkspace(config: AgenticROSConfig, inputs: Record, robot?: { safety?: RobotSafetyOverlay; } | null): SafetyCheckResult; /** * A body that accepts Twist. Profile `base` wins; with no profile, * anything except an arm-only cell is treated as having a base * (legacy configs default kind to "amr"). */ export declare function robotHasMobileBase(robot: ProfileRobot): boolean; export interface EmergencyStopResult { /** Resolved cmd_vel topic, when a stop was published. */ topic?: string; /** Present when this robot has no mobile base (arm-only). */ skipped?: "no_mobile_base"; } /** * Immediate emergency stop for one robot: five zero Twists on its * cmd_vel. Used by OpenClaw `/estop` and MCP/Gemini `ros2_estop`. * Does not cancel Nav2 or missions — that is `mission_cancel`. */ export declare function emergencyStopRobot(transport: RosTransport, robot: ProfileRobot, config?: { teleop?: { cmdVelTopic?: string; }; }): EmergencyStopResult; /** Best-effort zero Twist on every mobile-base robot sharing this transport. */ export declare function publishStopForBases(transport: RosTransport, robots: readonly ProfileRobot[]): Promise; /** * Publish zero Twist when the transport drops (and again on reconnect * so a stale last-command cannot resume). Returns an unsubscribe. */ export declare function attachDisconnectFailSafe(transport: RosTransport, robots: readonly ProfileRobot[]): () => void; export type LiveCheckSeverity = "green" | "yellow" | "red"; export interface LiveBindingCheck { id: string; robotId: string; key: string; name: string; severity: LiveCheckSeverity; reason: string; } export interface LiveGraphSnapshot { topics: ReadonlyArray<{ name: string; type?: string; }>; actions?: ReadonlyArray<{ name: string; type?: string; }>; } /** * Compare declared profile bindings against a live topic/action list. * Missing declared hardware is red; type mismatch is yellow. */ export declare function checkLiveBindings(robots: ReadonlyArray, graph: LiveGraphSnapshot): LiveBindingCheck[]; //# sourceMappingURL=safety.d.ts.map