Last active
April 25, 2026 13:00
-
-
Save dltj/644b91c959ffce4e8ea32318355767e4 to your computer and use it in GitHub Desktop.
Arduino program for Bluebird Box Door
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
| /* | |
| Bird box gate (servo) controller - Arduino Nano | |
| RF receiver is in MOMENTARY mode and drives a relay contact: | |
| Relay COM -> GND | |
| Relay NO -> D2 | |
| We use D2 with INPUT_PULLUP: | |
| - D2 reads HIGH normally | |
| - D2 reads LOW while the relay is energized (button held) | |
| Servo: | |
| - Signal on D9 | |
| - Servo powered from a solid external 5V rail | |
| Behavior: | |
| - On startup: command servo to 550 µs | |
| - Each button press toggles servo between 550 µs and 2360 µs | |
| */ | |
| #include <Servo.h> | |
| const int SERVO_PIN = 9; | |
| const int RF_PIN = 2; | |
| // Pulse widths in microseconds | |
| const int PULSE_CLOSED = 550; | |
| const int PULSE_OPEN = 2360; | |
| // Smooth motion tuning | |
| const int STEP_US = 5; // smaller = smoother, slower; larger = faster | |
| const int STEP_DELAY_MS = 10; // delay per step | |
| int currentPulse = PULSE_CLOSED; // track current command pulse width | |
| // Debounce / lockout | |
| const unsigned long DEBOUNCE_MS = 30; // relay contacts are pretty clean, but keep small debounce | |
| const unsigned long PRESS_LOCKOUT_MS = 250; // prevents multiple toggles if button is held | |
| Servo gateServo; | |
| bool isOpen = false; | |
| unsigned long lastToggleTime = 0; | |
| void moveServoSmoothTo(int targetPulse) { | |
| // Clamp to a reasonable range, just to be safe | |
| // Adjust if you truly want to allow wider pulses. | |
| if (targetPulse < 500) targetPulse = 500; | |
| if (targetPulse > 2500) targetPulse = 2500; | |
| int startPulse = currentPulse; | |
| int dir = (targetPulse > startPulse) ? +1 : -1; | |
| for (int p = startPulse; p != targetPulse; p += dir * STEP_US) { | |
| gateServo.writeMicroseconds(p); | |
| currentPulse = p; | |
| delay(STEP_DELAY_MS); | |
| } | |
| // Ensure final value is commanded exactly | |
| gateServo.writeMicroseconds(targetPulse); | |
| currentPulse = targetPulse; | |
| } | |
| void goClosed() { | |
| moveServoSmoothTo(PULSE_CLOSED); | |
| isOpen = false; | |
| } | |
| void goOpen() { | |
| moveServoSmoothTo(PULSE_OPEN); | |
| isOpen = true; | |
| } | |
| void toggleGate() { | |
| if (isOpen) goClosed(); | |
| else goOpen(); | |
| } | |
| void setup() { | |
| pinMode(RF_PIN, INPUT_PULLUP); | |
| gateServo.attach(SERVO_PIN); | |
| // Startup position | |
| goClosed(); | |
| delay(500); | |
| } | |
| void loop() { | |
| // Momentary relay closes to GND when pressed | |
| static bool lastStable = HIGH; | |
| static bool lastReading = HIGH; | |
| static unsigned long lastDebounceTime = 0; | |
| bool reading = digitalRead(RF_PIN); | |
| // Debounce: detect stable change | |
| if (reading != lastReading) { | |
| lastDebounceTime = millis(); | |
| lastReading = reading; | |
| } | |
| if (millis() - lastDebounceTime > DEBOUNCE_MS) { | |
| if (reading != lastStable) { | |
| lastStable = reading; | |
| // Treat HIGH->LOW transition as a button press event | |
| if (lastStable == LOW) { | |
| if (millis() - lastToggleTime > PRESS_LOCKOUT_MS) { | |
| lastToggleTime = millis(); | |
| toggleGate(); | |
| } | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment