// 2025 Nick H on behalf of Southfield Shooting Supplies
// This sketch allows 4 stepper motors (attached to targets) to be remotely controlled using a 4 button RF remote (YK04 module) similar to a remote fob for a car.
// The sketch is based on using an Arduino Uno paired with an Arduino UNO CNC Shield (which uses A4988 Stepper Motor Drivers) and a YK04 433 MHz remote control module
#include <Servo.h>
Servo Servos[4];
//Set Servo Pins for Servos 1-4
int ServoPins[]{ 3, 5, 6, 9 };
int ButtonPins[]{8, 10, 11, 12 };
//Use the array to represent the toggle status for 4 motors. Set the initial status for Motors 1-4 as 0. Using a toggle status allows the same button to be used to present and retract the target. The toggle status therefore represents whether the target in question is currently retracted (0) or presented (1)
int TStatus[]{ 0, 0, 0, 0 };
//Use the array to represent the toggle status for 4 buttons. Set the initial status for Buttons 1-4 as 0. Using a toggle status allows the same button to be used to present and retract the target. The toggle status therefore represents whether the button has been pressed an even or odd number of times for presenting and retracting the target
int BStatus[]{ 0, 0, 0, 0 };
//This is the initial code that runs on setup
void setup() {
// Set the inbuilt LED as output
pinMode(LED_BUILTIN, OUTPUT);
// Declare motor direction and step pins as output, the button pins as input: (This code assumes 4 motors and 4 buttons, each using a pin each)
for (int i = 0; i <= 3; i++) {
pinMode(ServoPins[i], OUTPUT);
Servos[i].attach(ServoPins[i]);
Servos[i].write(0);
pinMode(ButtonPins[i], INPUT_PULLUP);
}
// The built in LED will flash twice quickly during initial setup. This just acts as a diagnostic to show that the setup code is running.
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for half a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for half a second
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for half a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for half a second
for (int i = 0; i <= 3; i++) { // This provides another diagnostic in that it presents and retracts each target in turn with a 1 second gap in between to demonstrate the tha motors are working.
PresentTarget(i);
delay(1000);
RetractTarget(i);
delay(1000);
}
}
void loop() { //The code will repeat indefinitely. It loops around waiting for input from the pins on the RF receiver, which in turn represent pressing of the buttons on the remote control. If one of the pins is 'HIGH', then the corresponding button has been pressed on the remote.
for (int i = 0; i <= 3; i++) { // For each button, motor, target
BStatus[i] = digitalRead(ButtonPins[i]); //Read the status of the button pin
if ((BStatus[i]) == (TStatus[i])) {
//If the button status and target status match, then do nothing
} else if ((BStatus[i] == 0) && (TStatus[i] == 1)) { // If the button is not latched and the target is presented then retract the target
RetractTarget(i);
TStatus[i]=0; //Set the target status to 0 (Retracted)
} else if ((BStatus[i] == 1) && (TStatus[i] == 0)) { // If the button is latched and the target not presented then present the target
PresentTarget(i);
TStatus[i]=1; //Set the target status to 0 (Presented)
} else {
//Do nothing as there is not another valid combination
}
delay(50); //Delay to debounce the input pins representing the buttons
}
}
void PresentTarget(int TargetNumber) { //Funtion for presenting a selected target by spinning the relevant motor clockwise
Servos[TargetNumber].write(90);
}
void RetractTarget(int TargetNumber) { //Funtion for retracting a selected target by spinning the relevant motor clockwise
Servos[TargetNumber].write(0);
}