Created
February 5, 2025 14:56
-
-
Save jackwillis/705bb1e0cea4e02d7149cd386abda339 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ----- Ultrasonic Sensor ----- | |
| const int TRIG_PIN = 10; | |
| const int ECHO_PIN = 11; | |
| // ----- Piezoelectric buzzer ----- | |
| const int PIEZO_PIN = 8; | |
| // LED pins | |
| const int RED_LED_PIN = 3; // Red LED: No response or max distance | |
| const int YELLOW_LED_PIN = 5; // Yellow LED: Object detected at all | |
| const int GREEN_LED_PIN = 6; // Green LED: Object is within trigger zone | |
| const int BLUE_LED_PIN = 9; // Blue LED: Gate is active | |
| // ----- Distance & Smoothing Parameters ----- | |
| const float MIN_DISTANCE = 2.0; // cm (minimum valid reading) | |
| const float MAX_DISTANCE = 400.0; // cm (max or no response) | |
| const float DISTANCE_ALPHA = 0.1; // Smoothing factor for EMA (0 < alpha < 1) | |
| // ----- Gate (State Machine) Settings ----- | |
| const float GATE_TRIGGER_DISTANCE = 100.0; // cm (distance to trigger the gate) | |
| const unsigned long GATE_TRIGGER_TIME = 250; // ms (must stay in the trigger zone for this long) | |
| const float GATE_RELEASE_DISTANCE = 200.0; // cm (distance to release the gate) | |
| const unsigned long GATE_RELEASE_TIME = 1000; // ms (must stay beyond release distance for this long) | |
| // Distance measured by the ultrasonic sensor, in centimeters | |
| float distance = MAX_DISTANCE; | |
| float smoothedDistance = MAX_DISTANCE; | |
| // Gate state variables | |
| bool gateTriggered = false; // Indicates whether the gate is active | |
| unsigned long triggerStartTime = 0; // Timestamp when object enters the trigger zone | |
| unsigned long releaseStartTime = 0; // Timestamp when object moves beyond release zone | |
| // ----- Setup ----- | |
| void setup() { | |
| Serial.begin(115200); // Start serial communication for debugging | |
| // Initialize sensor pins | |
| pinMode(TRIG_PIN, OUTPUT); | |
| pinMode(ECHO_PIN, INPUT); | |
| // Initialize LED pins | |
| pinMode(RED_LED_PIN, OUTPUT); | |
| pinMode(YELLOW_LED_PIN, OUTPUT); | |
| pinMode(GREEN_LED_PIN, OUTPUT); | |
| pinMode(BLUE_LED_PIN, OUTPUT); | |
| // Seed the smoothing filter with an initial ultrasonic reading | |
| float initialDistance = readUltrasonic(); | |
| smoothedDistance = constrain(initialDistance, MIN_DISTANCE, MAX_DISTANCE); | |
| } | |
| // ----- Main Loop ----- | |
| void loop() { | |
| // Get the raw distance from the ultrasonic sensor | |
| distance = readUltrasonic(); | |
| // Apply the Exponential Moving Average (EMA) smoothing to the distance | |
| smoothedDistance = smoothDistance(distance); | |
| // Update the gate state based on the current distance | |
| updateGateState(); | |
| // Update the LEDs based on the gate state and current distance | |
| updateLEDs(); | |
| // Beep with piezo if gate state changes | |
| beepOnGateStateChange(); | |
| // Debugging: Output distance and gate state to the serial monitor | |
| Serial.print("Raw Distance: "); | |
| Serial.print(distance); | |
| Serial.print(" cm, Smoothed Distance: "); | |
| Serial.print(smoothedDistance); | |
| Serial.print(" cm, Gate: "); | |
| Serial.println(gateTriggered ? "TRIGGERED" : "OFF"); | |
| } | |
| // ----- Function to Read Ultrasonic Distance ----- | |
| /* | |
| This function sends a pulse to the ultrasonic sensor and measures the duration | |
| it takes for the echo to return, converting that duration into distance (in cm). | |
| */ | |
| float readUltrasonic() { | |
| digitalWrite(TRIG_PIN, LOW); | |
| delayMicroseconds(2); | |
| digitalWrite(TRIG_PIN, HIGH); | |
| delayMicroseconds(10); | |
| digitalWrite(TRIG_PIN, LOW); | |
| long duration = pulseIn(ECHO_PIN, HIGH, 30000); // Timeout after 30ms | |
| return (duration == 0) ? MAX_DISTANCE : (duration * 0.0343) / 2.0; // Return the calculated distance in cm | |
| } | |
| // ----- Exponential Moving Average (EMA) for Distance ----- | |
| /* | |
| This function applies the Exponential Moving Average (EMA) to the distance. | |
| It smooths out sensor noise and makes the transition between distances more stable. | |
| */ | |
| float smoothDistance(float newDistance) { | |
| return DISTANCE_ALPHA * newDistance + (1 - DISTANCE_ALPHA) * smoothedDistance; | |
| } | |
| // ----- Gate State Machine ----- | |
| /* | |
| This function handles the logic of triggering and releasing the gate based on | |
| the smoothed distance. It uses the configured thresholds for triggering and releasing. | |
| */ | |
| void updateGateState() { | |
| unsigned long now = millis(); // Get the current time in milliseconds | |
| // If distance exceeds MAX_DISTANCE, reset the gate and timers | |
| if (smoothedDistance >= MAX_DISTANCE) { | |
| gateTriggered = false; | |
| triggerStartTime = releaseStartTime = 0; | |
| return; | |
| } | |
| // Gate not yet triggered: Check if the object is within the trigger distance | |
| if (!gateTriggered && smoothedDistance < GATE_TRIGGER_DISTANCE) { | |
| if (triggerStartTime == 0) { | |
| triggerStartTime = now; // Start the timer if object enters trigger zone | |
| } | |
| if (now - triggerStartTime >= GATE_TRIGGER_TIME) { | |
| gateTriggered = true; // Gate is triggered after staying in the zone for enough time | |
| releaseStartTime = 0; // Reset release timer when gate is triggered | |
| } | |
| return; // Exit function if gate is triggered | |
| } | |
| // Gate is triggered: Check if object moves beyond the release distance to reset | |
| if (gateTriggered && smoothedDistance > GATE_RELEASE_DISTANCE) { | |
| if (releaseStartTime == 0) { | |
| releaseStartTime = now; // Start the release timer | |
| } | |
| if (now - releaseStartTime >= GATE_RELEASE_TIME) { | |
| gateTriggered = false; // Reset the gate after staying beyond the release zone | |
| triggerStartTime = 0; | |
| } | |
| } else { | |
| // If object moves back into the trigger zone, reset release timer | |
| releaseStartTime = 0; | |
| } | |
| } | |
| // ----- LED Control ----- | |
| /* | |
| - Red LED brightness represents smoothedDistance (far = dim, close = bright) | |
| - Yellow LED lights up when the object is detected | |
| - Green LED turns on when close enough to trigger the gate | |
| - Blue LED fades in/out smoothly when the gate transitions | |
| */ | |
| void updateLEDs() { | |
| static int blueBrightness = 0; // Current blue LED brightness | |
| static int targetBrightness = 0; // Target brightness (0 or 255) | |
| // Map smoothedDistance to PWM brightness for the red LED (far = dim, close = bright) | |
| int redBrightness = map(constrain(smoothedDistance, MIN_DISTANCE, MAX_DISTANCE), | |
| MIN_DISTANCE, MAX_DISTANCE, 255, 10); | |
| analogWrite(RED_LED_PIN, redBrightness); | |
| // Yellow LED: Lights up when an object is close enough to maintain the gate | |
| digitalWrite(YELLOW_LED_PIN, smoothedDistance < GATE_RELEASE_DISTANCE); | |
| // Green LED: Lights up when the object is close enough to trigger the gate | |
| digitalWrite(GREEN_LED_PIN, smoothedDistance < GATE_TRIGGER_DISTANCE); | |
| // Update target brightness based on gate state | |
| targetBrightness = gateTriggered ? 255 : 0; | |
| // Smooth transition: Adjust brightness gradually | |
| if (blueBrightness < targetBrightness) { | |
| blueBrightness += 5; // Increase brightness | |
| if (blueBrightness > targetBrightness) blueBrightness = targetBrightness; | |
| } else if (blueBrightness > targetBrightness) { | |
| blueBrightness -= 5; // Decrease brightness | |
| if (blueBrightness < targetBrightness) blueBrightness = targetBrightness; | |
| } | |
| // Apply smoothed brightness | |
| analogWrite(BLUE_LED_PIN, blueBrightness); | |
| } | |
| // ----- Beep Function (Piezo Buzzer) ----- | |
| /* | |
| This function plays a beep when the gate's state changes. It plays a higher pitch beep | |
| when the gate is triggered (entering), and a lower pitch when the gate is released (leaving). | |
| */ | |
| void beepOnGateStateChange() { | |
| static bool lastGateState = false; // Track the last gate state | |
| // If the gate state changed from triggered to untriggered or vice versa | |
| if (gateTriggered != lastGateState) { | |
| if (gateTriggered) { | |
| // Beep when the gate is triggered (object enters) | |
| tone(PIEZO_PIN, 1000, 200); // 1000Hz tone for 200ms | |
| } else { | |
| // Beep when the gate is released (object leaves) | |
| tone(PIEZO_PIN, 500, 200); // 500Hz tone for 200ms | |
| } | |
| lastGateState = gateTriggered; // Update the last gate state | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment