Worker safety and compliance monitoring using WiFi CSI signals. Works through dust, smoke, shelving, and walls where cameras fail. Designed for warehouses, factories, clean rooms, farms, and construction sites.
ADR-041 Category 5 | Event IDs 500--599 | Crate wifi-densepose-wasm-edge
These modules are supplementary monitoring tools. They do NOT replace:
- Certified safety systems (SIL-rated controllers, safety PLCs)
- Gas detectors, O2 monitors, or LEL sensors
- OSHA-required personal protective equipment
- Physical barriers, guardrails, or interlocks
- Trained safety attendants or rescue teams
Always deploy alongside certified primary safety systems. WiFi CSI sensing is susceptible to environmental changes (new metal objects, humidity, temperature) that can cause false negatives. Calibrate regularly and validate against ground truth.
| Module | File | What It Does | Event IDs | Budget |
|---|---|---|---|---|
| Forklift Proximity | ind_forklift_proximity.rs |
Warns when pedestrians are near moving forklifts/AGVs | 500--502 | S (<5 ms) |
| Confined Space | ind_confined_space.rs |
Monitors worker vitals in tanks, manholes, vessels | 510--514 | L (<2 ms) |
| Clean Room | ind_clean_room.rs |
Personnel count and turbulent motion for ISO 14644 | 520--523 | L (<2 ms) |
| Livestock Monitor | ind_livestock_monitor.rs |
Animal health monitoring in pens, barns, enclosures | 530--533 | L (<2 ms) |
| Structural Vibration | ind_structural_vibration.rs |
Seismic, resonance, and structural drift detection | 540--543 | H (<10 ms) |
What it does: Warns when a person is too close to a moving forklift, AGV, or mobile robot, even around blind corners and through shelving racks.
How it works: The module separates forklift signatures from human signatures using three CSI features:
- Amplitude ratio: Large metal bodies (forklifts) produce 2--5x amplitude increases across all subcarriers relative to an empty-warehouse baseline.
- Low-frequency phase dominance: Forklifts move slowly (<0.3 Hz phase modulation) compared to walking humans (0.5--2 Hz). The module computes the ratio of low-frequency energy to total phase energy.
- Motor vibration: Electric forklift motors produce elevated, uniform variance across subcarriers (>0.08 threshold).
When all three conditions are met for 4 consecutive frames (debounced), the module declares a vehicle present. If a human signature (host-reported presence + motion energy >0.15) co-occurs, a proximity warning is emitted with a distance category derived from amplitude ratio.
pub struct ForkliftProximityDetector { /* ... */ }
impl ForkliftProximityDetector {
/// Create a new detector. Requires 100-frame calibration (~5 s at 20 Hz).
pub const fn new() -> Self;
/// Process one CSI frame. Returns events as (event_id, value) pairs.
pub fn process_frame(
&mut self,
phases: &[f32], // per-subcarrier phase values
amplitudes: &[f32], // per-subcarrier amplitude values
variance: &[f32], // per-subcarrier variance values
motion_energy: f32, // host-reported motion energy
presence: i32, // host-reported presence flag (0/1)
n_persons: i32, // host-reported person count
) -> &[(i32, f32)];
/// Whether a vehicle is currently detected.
pub fn is_vehicle_present(&self) -> bool;
/// Current amplitude ratio (proxy for vehicle proximity).
pub fn amplitude_ratio(&self) -> f32;
}| Event ID | Constant | Value | Meaning |
|---|---|---|---|
| 500 | EVENT_PROXIMITY_WARNING |
Distance category: 0.0 = critical, 1.0 = warning, 2.0 = caution | Person dangerously close to vehicle |
| 501 | EVENT_VEHICLE_DETECTED |
Amplitude ratio (float) | Forklift/AGV entered sensor zone |
| 502 | EVENT_HUMAN_NEAR_VEHICLE |
Motion energy (float) | Human detected in vehicle zone (fires once on transition) |
+-----------+
| |
+-------->| No Vehicle|<---------+
| | | |
| +-----+-----+ |
| | |
| amp_ratio > 2.5 AND |
| low_freq_dominant AND | debounce drops
| vibration > 0.08 | below threshold
| (4 frames debounce) |
| | |
| +-----v-----+ |
| | |----------+
+---------| Vehicle |
| Present |
+-----+-----+
|
human present | (presence + motion > 0.15)
+ debounce |
+-----v-----+
| Proximity |----> EVENT 500 (cooldown 40 frames)
| Warning |----> EVENT 502 (once on transition)
+-----------+
| Parameter | Default | Range | Safety Implication |
|---|---|---|---|
FORKLIFT_AMP_RATIO |
2.5 | 1.5--5.0 | Lower = more sensitive, more false positives |
HUMAN_MOTION_THRESH |
0.15 | 0.05--0.5 | Lower = catches slow-moving workers |
VEHICLE_DEBOUNCE |
4 frames | 2--10 | Higher = fewer false alarms, slower response |
PROXIMITY_DEBOUNCE |
2 frames | 1--5 | Higher = fewer false alarms, slower response |
ALERT_COOLDOWN |
40 frames (2 s) | 10--200 | Lower = more frequent warnings |
DIST_CRITICAL |
amp ratio > 4.0 | -- | Very close proximity |
DIST_WARNING |
amp ratio > 3.0 | -- | Close proximity |
use wifi_densepose_wasm_edge::ind_forklift_proximity::ForkliftProximityDetector;
let mut detector = ForkliftProximityDetector::new();
// Calibration phase: feed 100 frames of empty warehouse
for _ in 0..100 {
detector.process_frame(&phases, &s, &variance, 0.0, 0, 0);
}
// Normal operation
let events = detector.process_frame(&phases, &s, &variance, 0.5, 1, 1);
for &(event_id, value) in events {
match event_id {
500 => {
let category = match value as i32 {
0 => "CRITICAL -- stop forklift immediately",
1 => "WARNING -- reduce speed",
_ => "CAUTION -- be alert",
};
trigger_alarm(category);
}
501 => log("Vehicle detected, amplitude ratio: {}", value),
502 => log("Human entered vehicle zone"),
_ => {}
}
}-
Sensor placement: Mount one ESP32 WiFi sensor per aisle, at shelf height (1.5--2 m). Each sensor covers approximately one aisle width (3--4 m) and 10--15 m of aisle length.
-
Calibration: Power on during a quiet period (no forklifts, no workers). The module auto-calibrates over the first 100 frames (5 s at 20 Hz). The baseline amplitude represents the empty aisle.
-
Threshold tuning: If false alarms occur due to hand trucks or pallet jacks, increase
FORKLIFT_AMP_RATIOfrom 2.5 to 3.0. If forklifts are missed, decrease to 2.0. -
Integration: Connect
EVENT_PROXIMITY_WARNING(500) to a warning light (amber for caution/warning, red for critical) and audible alarm. Connect to the facility SCADA system for logging. -
Validation: Walk through the aisle while a forklift operates. Verify all three distance categories trigger at appropriate ranges.
What it does: Monitors workers inside tanks, manholes, vessels, or any enclosed space. Confirms they are breathing and alerts if they stop moving or breathing.
Compliance: Designed to support OSHA 29 CFR 1910.146 confined space entry requirements. The module provides continuous proof-of-life monitoring to supplement (not replace) the required safety attendant.
How it works: Uses debounced presence detection to track entry/exit transitions. While a worker is inside, the module continuously monitors two vital indicators:
- Breathing: Host-reported breathing BPM must stay above 4.0 BPM. If breathing is not detected for 300 frames (15 seconds at 20 Hz), an extraction alert is emitted.
- Motion: Host-reported motion energy must stay above 0.02. If no motion is detected for 1200 frames (60 seconds), an immobility alert is emitted.
The module transitions between Empty, Present, BreathingCeased, and
Immobile states. When breathing or motion resumes, the state recovers
back to Present.
pub enum WorkerState {
Empty, // No worker in the space
Present, // Worker present, vitals normal
BreathingCeased, // No breathing detected (danger)
Immobile, // No motion detected (danger)
}
pub struct ConfinedSpaceMonitor { /* ... */ }
impl ConfinedSpaceMonitor {
pub const fn new() -> Self;
/// Process one frame.
pub fn process_frame(
&mut self,
presence: i32, // host-reported presence (0/1)
breathing_bpm: f32, // host-reported breathing rate
motion_energy: f32, // host-reported motion energy
variance: f32, // mean CSI variance
) -> &[(i32, f32)];
/// Current worker state.
pub fn state(&self) -> WorkerState;
/// Whether a worker is inside the space.
pub fn is_worker_inside(&self) -> bool;
/// Seconds since last confirmed breathing.
pub fn seconds_since_breathing(&self) -> f32;
/// Seconds since last detected motion.
pub fn seconds_since_motion(&self) -> f32;
}| Event ID | Constant | Value | Meaning |
|---|---|---|---|
| 510 | EVENT_WORKER_ENTRY |
1.0 | Worker entered the confined space |
| 511 | EVENT_WORKER_EXIT |
1.0 | Worker exited the confined space |
| 512 | EVENT_BREATHING_OK |
BPM (float) | Periodic breathing confirmation (~every 5 s) |
| 513 | EVENT_EXTRACTION_ALERT |
Seconds since last breath | No breathing for >15 s -- initiate rescue |
| 514 | EVENT_IMMOBILE_ALERT |
Seconds without motion | No motion for >60 s -- check on worker |
+---------+
| Empty |<----------+
+----+----+ |
| |
presence | | absence (10 frames)
(10 frames) | |
v |
+---------+ |
+------>| Present |-----------+
| +----+----+
| | |
| breathing | no | no motion
| resumes | breathing| (1200 frames)
| | (300 |
| | frames) |
| +----v------+ |
+-------|Breathing | |
| | Ceased | |
| +-----------+ |
| |
| +-----------+ |
+-------| Immobile |<--+
+-----------+
motion resumes -> Present
| Parameter | Default | Range | Safety Implication |
|---|---|---|---|
BREATHING_CEASE_FRAMES |
300 (15 s) | 100--600 | Lower = faster alert, more false positives |
IMMOBILE_FRAMES |
1200 (60 s) | 400--3600 | Lower = catches slower collapses |
MIN_BREATHING_BPM |
4.0 | 2.0--8.0 | Lower = more tolerant of slow breathing |
MIN_MOTION_ENERGY |
0.02 | 0.005--0.1 | Lower = catches subtle movements |
ENTRY_EXIT_DEBOUNCE |
10 frames | 5--30 | Higher = fewer false entry/exits |
MIN_PRESENCE_VAR |
0.005 | 0.001--0.05 | Noise rejection for empty space |
use wifi_densepose_wasm_edge::ind_confined_space::{
ConfinedSpaceMonitor, WorkerState,
EVENT_EXTRACTION_ALERT, EVENT_IMMOBILE_ALERT,
};
let mut monitor = ConfinedSpaceMonitor::new();
// Process each CSI frame
let events = monitor.process_frame(presence, breathing_bpm, motion_energy, variance);
for &(event_id, value) in events {
match event_id {
513 => { // EXTRACTION_ALERT
activate_rescue_alarm();
notify_safety_attendant(value); // seconds since last breath
}
514 => { // IMMOBILE_ALERT
notify_safety_attendant(value); // seconds without motion
}
_ => {}
}
}
// Query state for dashboard display
match monitor.state() {
WorkerState::Empty => display_green("Space empty"),
WorkerState::Present => display_green("Worker OK"),
WorkerState::BreathingCeased => display_red("NO BREATHING"),
WorkerState::Immobile => display_amber("Worker immobile"),
}What it does: Tracks personnel count and movement patterns in cleanrooms to enforce ISO 14644 occupancy limits and detect turbulent motion that could disturb laminar airflow.
How it works: Uses the host-reported person count with debounced violation detection. Turbulent motion (rapid movement with energy >0.6) is flagged because it disrupts the laminar airflow that keeps particulate counts low. The module maintains a running compliance percentage for audit reporting.
pub struct CleanRoomMonitor { /* ... */ }
impl CleanRoomMonitor {
/// Create with default max occupancy of 4.
pub const fn new() -> Self;
/// Create with custom maximum occupancy.
pub const fn with_max_occupancy(max: u8) -> Self;
/// Process one frame.
pub fn process_frame(
&mut self,
n_persons: i32, // host-reported person count
presence: i32, // host-reported presence (0/1)
motion_energy: f32, // host-reported motion energy
) -> &[(i32, f32)];
/// Current occupancy count.
pub fn current_count(&self) -> u8;
/// Maximum allowed occupancy.
pub fn max_occupancy(&self) -> u8;
/// Whether currently in violation.
pub fn is_in_violation(&self) -> bool;
/// Compliance percentage (0--100).
pub fn compliance_percent(&self) -> f32;
/// Total number of violation events.
pub fn total_violations(&self) -> u32;
}| Event ID | Constant | Value | Meaning |
|---|---|---|---|
| 520 | EVENT_OCCUPANCY_COUNT |
Person count (float) | Occupancy changed |
| 521 | EVENT_OCCUPANCY_VIOLATION |
Current count (float) | Count exceeds max allowed |
| 522 | EVENT_TURBULENT_MOTION |
Motion energy (float) | Rapid movement detected (airflow risk) |
| 523 | EVENT_COMPLIANCE_REPORT |
Compliance % (0--100) | Periodic compliance summary (~30 s) |
+------------------+
| Monitoring |
| (count <= max) |
+--------+---------+
| count > max
| (10 frames debounce)
+--------v---------+
| Violation |----> EVENT 521 (cooldown 200 frames)
| (count > max) |
+--------+---------+
| count <= max
|
+--------v---------+
| Monitoring |
+------------------+
Parallel:
motion_energy > 0.6 (3 frames) ----> EVENT 522 (cooldown 100 frames)
Every 600 frames (~30 s) ----------> EVENT 523 (compliance %)
| Parameter | Default | Range | Safety Implication |
|---|---|---|---|
DEFAULT_MAX_OCCUPANCY |
4 | 1--255 | Per ISO 14644 room class |
TURBULENT_MOTION_THRESH |
0.6 | 0.3--0.9 | Lower = stricter movement control |
VIOLATION_DEBOUNCE |
10 frames | 3--20 | Higher = tolerates brief over-counts |
VIOLATION_COOLDOWN |
200 frames (10 s) | 40--600 | Alert repeat interval |
COMPLIANCE_REPORT_INTERVAL |
600 frames (30 s) | 200--6000 | Audit report frequency |
use wifi_densepose_wasm_edge::ind_clean_room::{
CleanRoomMonitor, EVENT_OCCUPANCY_VIOLATION, EVENT_COMPLIANCE_REPORT,
};
// ISO Class 5 cleanroom: max 3 personnel
let mut monitor = CleanRoomMonitor::with_max_occupancy(3);
let events = monitor.process_frame(n_persons, presence, motion_energy);
for &(event_id, value) in events {
match event_id {
521 => alert_cleanroom_supervisor(value as u8),
522 => alert_turbulent_motion(),
523 => log_compliance_audit(value),
_ => {}
}
}
// Dashboard
println!("Occupancy: {}/{}", monitor.current_count(), monitor.max_occupancy());
println!("Compliance: {:.1}%", monitor.compliance_percent());What it does: Monitors animal presence and health in pens, barns, and enclosures. Detects abnormal stillness (possible illness), labored breathing, and escape events.
How it works: Tracks presence with debounced entry/exit detection. Monitors breathing rate against species-specific normal ranges. Detects prolonged stillness (>5 minutes) as a sign of illness, and sudden absence after confirmed presence as an escape event.
Species-specific breathing ranges:
| Species | Normal BPM | Labored: below | Labored: above |
|---|---|---|---|
| Cattle | 12--30 | 8.4 (0.7x min) | 39.0 (1.3x max) |
| Sheep | 12--20 | 8.4 (0.7x min) | 26.0 (1.3x max) |
| Poultry | 15--30 | 10.5 (0.7x min) | 39.0 (1.3x max) |
| Custom | configurable | 0.7x min | 1.3x max |
pub enum Species {
Cattle,
Sheep,
Poultry,
Custom { min_bpm: f32, max_bpm: f32 },
}
pub struct LivestockMonitor { /* ... */ }
impl LivestockMonitor {
/// Create with default species (Cattle).
pub const fn new() -> Self;
/// Create with a specific species.
pub const fn with_species(species: Species) -> Self;
/// Process one frame.
pub fn process_frame(
&mut self,
presence: i32, // host-reported presence (0/1)
breathing_bpm: f32, // host-reported breathing rate
motion_energy: f32, // host-reported motion energy
variance: f32, // mean CSI variance (unused, reserved)
) -> &[(i32, f32)];
/// Whether an animal is currently detected.
pub fn is_animal_present(&self) -> bool;
/// Configured species.
pub fn species(&self) -> Species;
/// Minutes of stillness.
pub fn stillness_minutes(&self) -> f32;
/// Last observed breathing BPM.
pub fn last_breathing_bpm(&self) -> f32;
}| Event ID | Constant | Value | Meaning |
|---|---|---|---|
| 530 | EVENT_ANIMAL_PRESENT |
BPM (float) | Periodic presence report (~10 s) |
| 531 | EVENT_ABNORMAL_STILLNESS |
Minutes still (float) | No motion for >5 minutes |
| 532 | EVENT_LABORED_BREATHING |
BPM (float) | Breathing outside normal range |
| 533 | EVENT_ESCAPE_ALERT |
Minutes present before escape (float) | Animal suddenly absent after confirmed presence |
+---------+
| Empty |<---------+
+----+----+ |
| |
presence | absence >= 20 frames
(10 frames) | (after >= 200 frames presence
v | -> EVENT 533 escape alert)
+---------+ |
| Present |----------+
+----+----+
|
no motion (6000 frames = 5 min) -> EVENT 531 (once)
breathing outside range (20 frames) -> EVENT 532 (repeating)
| Parameter | Default | Range | Safety Implication |
|---|---|---|---|
STILLNESS_FRAMES |
6000 (5 min) | 1200--12000 | Lower = earlier illness detection |
MIN_PRESENCE_FOR_ESCAPE |
200 (10 s) | 60--600 | Minimum presence before escape counts |
ESCAPE_ABSENCE_FRAMES |
20 (1 s) | 10--100 | Brief absences tolerated |
LABORED_DEBOUNCE |
20 frames (1 s) | 5--60 | Lower = faster breathing alerts |
MIN_MOTION_ACTIVE |
0.03 | 0.01--0.1 | Sensitivity to subtle movement |
use wifi_densepose_wasm_edge::ind_livestock_monitor::{
LivestockMonitor, Species, EVENT_ESCAPE_ALERT, EVENT_LABORED_BREATHING,
};
// Dairy barn: monitor cows
let mut monitor = LivestockMonitor::with_species(Species::Cattle);
let events = monitor.process_frame(presence, breathing_bpm, motion_energy, variance);
for &(event_id, value) in events {
match event_id {
532 => alert_veterinarian(value), // labored breathing BPM
533 => alert_farm_security(value), // escape: minutes present before loss
531 => log_health_concern(value), // minutes of stillness
_ => {}
}
}What it does: Detects building vibration, seismic activity, and structural stress using CSI phase stability. Only operates when the monitored space is unoccupied (human movement masks structural signals).
How it works: When no humans are present, WiFi CSI phase is highly stable (noise floor ~0.02 rad). The module detects three types of structural events:
- Seismic: Broadband energy increase (>60% of subcarriers affected, RMS >0.15 rad). Indicates earthquake, heavy vehicle pass-by, or construction activity.
- Mechanical resonance: Narrowband peaks detected via autocorrelation of the mean-phase time series. A peak-to-mean ratio >3.0 with RMS above 2x noise floor indicates periodic mechanical vibration (HVAC, pumps, rotating equipment).
- Structural drift: Slow monotonic phase change across >50% of subcarriers for >30 seconds. Indicates material stress, foundation settlement, or thermal expansion.
pub struct StructuralVibrationMonitor { /* ... */ }
impl StructuralVibrationMonitor {
/// Create a new monitor. Requires 100-frame calibration when empty.
pub const fn new() -> Self;
/// Process one CSI frame.
pub fn process_frame(
&mut self,
phases: &[f32], // per-subcarrier phase values
amplitudes: &[f32], // per-subcarrier amplitude values
variance: &[f32], // per-subcarrier variance values
presence: i32, // 0 = empty (analyze), 1 = occupied (skip)
) -> &[(i32, f32)];
/// Current RMS vibration level.
pub fn rms_vibration(&self) -> f32;
/// Whether baseline has been established.
pub fn is_calibrated(&self) -> bool;
}| Event ID | Constant | Value | Meaning |
|---|---|---|---|
| 540 | EVENT_SEISMIC_DETECTED |
RMS vibration level (rad) | Broadband seismic activity |
| 541 | EVENT_MECHANICAL_RESONANCE |
Dominant frequency (Hz) | Narrowband mechanical vibration |
| 542 | EVENT_STRUCTURAL_DRIFT |
Drift rate (rad/s) | Slow structural deformation |
| 543 | EVENT_VIBRATION_SPECTRUM |
RMS level (rad) | Periodic spectrum report (~5 s) |
+--------------+
| Calibrating | (100 frames, presence=0 required)
+------+-------+
|
+------v-------+
| Idle | (presence=1: skip analysis, reset drift)
| (Occupied) |
+------+-------+
| presence=0
+------v-------+
| Analyzing |
+------+-------+
|
+-----> RMS > 0.15 + broadband -------> EVENT 540 (seismic)
+-----> autocorr peak ratio > 3.0 ----> EVENT 541 (resonance)
+-----> monotonic drift > 30 s -------> EVENT 542 (drift)
+-----> every 100 frames -------------> EVENT 543 (spectrum)
| Parameter | Default | Range | Safety Implication |
|---|---|---|---|
SEISMIC_THRESH |
0.15 rad RMS | 0.05--0.5 | Lower = more sensitive to tremors |
RESONANCE_PEAK_RATIO |
3.0 | 2.0--5.0 | Lower = detects weaker resonances |
DRIFT_RATE_THRESH |
0.0005 rad/frame | 0.0001--0.005 | Lower = detects slower drift |
DRIFT_MIN_FRAMES |
600 (30 s) | 200--2400 | Minimum drift duration before alert |
SEISMIC_DEBOUNCE |
4 frames | 2--10 | Higher = fewer false seismic alerts |
SEISMIC_COOLDOWN |
200 frames (10 s) | 40--600 | Alert repeat interval |
use wifi_densepose_wasm_edge::ind_structural_vibration::{
StructuralVibrationMonitor, EVENT_SEISMIC_DETECTED, EVENT_STRUCTURAL_DRIFT,
};
let mut monitor = StructuralVibrationMonitor::new();
// Calibrate during unoccupied period
for _ in 0..100 {
monitor.process_frame(&phases, &s, &variance, 0);
}
assert!(monitor.is_calibrated());
// Normal operation
let events = monitor.process_frame(&phases, &s, &variance, presence);
for &(event_id, value) in events {
match event_id {
540 => {
trigger_building_alarm();
log_seismic_event(value); // RMS vibration level
}
542 => {
notify_structural_engineer(value); // drift rate rad/s
}
_ => {}
}
}- Standard: Powered Industrial Trucks -- operator must warn others.
- Module supports: Automated proximity detection supplements horn/light warnings. Does NOT replace operator training, seat belts, or speed limits.
- Additional equipment required: Physical barriers, floor markings, traffic mirrors, operator training program.
- Standard: Permit-Required Confined Spaces.
- Module supports: Continuous proof-of-life monitoring (breathing and motion confirmation). Assists the required safety attendant.
- Additional equipment required:
- Atmospheric monitoring (O2, H2S, CO, LEL) -- the WiFi module cannot detect gas hazards.
- Communication system between entrant and attendant.
- Rescue equipment (retrieval system, harness, tripod).
- Entry permit documenting hazards and controls.
- Audit trail:
EVENT_BREATHING_OK(512) provides timestamped proof-of-life records for compliance documentation.
- Standard: Cleanrooms and associated controlled environments.
- Module supports: Real-time occupancy enforcement and turbulent motion detection for particulate control.
- Additional equipment required: Particle counters, differential pressure monitors, HEPA/ULPA filtration systems.
- Documentation:
EVENT_COMPLIANCE_REPORT(523) provides periodic compliance percentages for audit records.
- Module supports: Automated health monitoring reduces manual inspection burden. Escape detection supports perimeter security.
- Additional equipment required: Veterinary monitoring systems, proper fencing, temperature/humidity sensors.
- Standard: Structural stability requirements for construction.
- Module supports: Continuous vibration monitoring during unoccupied periods. Seismic detection provides early warning.
- Additional equipment required: Certified structural inspection, accelerometers for critical structures, tilt sensors.
+---+---+---+---+---+
| S | | | | S | S = WiFi sensor (ESP32)
+---+ Aisle 1 +---+ Mounted at shelf height (1.5-2 m)
| | | | One sensor per aisle intersection
+---+ Aisle 2 +---+
| S | | S | Coverage: ~15 m range per sensor
+---+---+---+---+---+ For proximity: sensor every 10 m along aisle
- Mount sensors at shelf height (1.5--2 m) for best human/forklift separation.
- Place at aisle intersections for blind-corner coverage.
- Each sensor covers approximately 10--15 m of aisle length.
- For critical zones (loading docks, charging areas), use overlapping sensors.
Ground Level
+-----------+
| Sensor A | <-- Entry point monitoring
+-----+-----+
|
| Manhole / Hatch
|
+-----v-----+
| Sensor B | <-- Inside space (if possible)
+-----------+
- Sensor A at the entry point detects worker entry/exit.
- Sensor B inside the confined space (if safely mountable) provides breathing and motion monitoring.
- If only one sensor is available, mount at the entry facing into the space.
- WiFi signals penetrate metal walls poorly -- use multiple sensors for large vessels.
Connect ESP32 event output to safety PLCs via:
- UDP: The sensing server receives ESP32 CSI data and emits events
via REST API. Poll
/api/v1/eventsfor real-time alerts. - Modbus TCP: Use a gateway to convert UDP events to Modbus registers for direct PLC integration.
- GPIO: For hard-wired safety circuits, connect ESP32 GPIO outputs to PLC safety inputs. Configure the ESP32 firmware to assert GPIO on specific event IDs.
- Ensure the monitored space is in its normal empty state.
- Power on the sensor and wait for calibration to complete:
- Forklift Proximity: 100 frames (5 seconds)
- Structural Vibration: 100 frames (5 seconds)
- Confined Space: No calibration needed (uses host presence)
- Clean Room: No calibration needed (uses host person count)
- Livestock: No calibration needed (uses host presence)
- Validate by walking through the space and confirming presence detection.
- For forklift proximity, drive a forklift through and verify vehicle detection and proximity warnings at appropriate distances.
- Document calibration date, sensor position, and firmware version.
| Range | Module | Events |
|---|---|---|
| 500--502 | Forklift Proximity | PROXIMITY_WARNING, VEHICLE_DETECTED, HUMAN_NEAR_VEHICLE |
| 510--514 | Confined Space | WORKER_ENTRY, WORKER_EXIT, BREATHING_OK, EXTRACTION_ALERT, IMMOBILE_ALERT |
| 520--523 | Clean Room | OCCUPANCY_COUNT, OCCUPANCY_VIOLATION, TURBULENT_MOTION, COMPLIANCE_REPORT |
| 530--533 | Livestock Monitor | ANIMAL_PRESENT, ABNORMAL_STILLNESS, LABORED_BREATHING, ESCAPE_ALERT |
| 540--543 | Structural Vibration | SEISMIC_DETECTED, MECHANICAL_RESONANCE, STRUCTURAL_DRIFT, VIBRATION_SPECTRUM |
Total: 20 event types across 5 modules.