diff --git a/ColorComposer/SpectralFM/include/Debug.h b/ColorComposer/SpectralFM/include/Debug.h index ad9c937..caf3ffa 100644 --- a/ColorComposer/SpectralFM/include/Debug.h +++ b/ColorComposer/SpectralFM/include/Debug.h @@ -2,10 +2,10 @@ * This is a macro for easily enabling or disabling the Serial monitor print statements. * * You can enable serial print debugging by setting - * #define USE_SERIAL 1 + * #define USE_SERIAL * - * Or, you can disable serial print debugging by setting - * #define USE_SERIAL 0 + * Or, you can disable serial print debugging by not setting it + * // #define USE_SERIAL * * In your main code, rather than using Serial.print() or Serial.println(), use their aliases defined below (e.g., SERIAL_PRINTLN()). * @@ -26,18 +26,16 @@ // #define USE_SERIAL -#if USE_SERIAL +#ifdef USE_SERIAL + #define SERIAL_BEGIN(x) Serial.begin(x) #define SERIAL_PRINT(x) Serial.print(x) #define SERIAL_PRINTLN(x) Serial.println(x) - #define SERIAL_BEGIN(baud) Serial.begin(baud) #define SERIAL_TAB Serial.print("\t") - #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("t");} - #define SERIAL_BEGIN(x) Serial.begin(x) + #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("\t");} #else + #define SERIAL_BEGIN(x) do {} while (0) #define SERIAL_PRINT(x) do {} while (0) #define SERIAL_PRINTLN(x) do {} while (0) - #define SERIAL_BEGIN(baud) do {} while (0) #define SERIAL_TAB do {} while (0) #define SERIAL_TABS(x) do {} while (0) - #define SERIAL_BEGIN(x) do {} while (0) #endif diff --git a/ColorComposer/StockCode/include/Debug.h b/ColorComposer/StockCode/include/Debug.h index ad9c937..caf3ffa 100644 --- a/ColorComposer/StockCode/include/Debug.h +++ b/ColorComposer/StockCode/include/Debug.h @@ -2,10 +2,10 @@ * This is a macro for easily enabling or disabling the Serial monitor print statements. * * You can enable serial print debugging by setting - * #define USE_SERIAL 1 + * #define USE_SERIAL * - * Or, you can disable serial print debugging by setting - * #define USE_SERIAL 0 + * Or, you can disable serial print debugging by not setting it + * // #define USE_SERIAL * * In your main code, rather than using Serial.print() or Serial.println(), use their aliases defined below (e.g., SERIAL_PRINTLN()). * @@ -26,18 +26,16 @@ // #define USE_SERIAL -#if USE_SERIAL +#ifdef USE_SERIAL + #define SERIAL_BEGIN(x) Serial.begin(x) #define SERIAL_PRINT(x) Serial.print(x) #define SERIAL_PRINTLN(x) Serial.println(x) - #define SERIAL_BEGIN(baud) Serial.begin(baud) #define SERIAL_TAB Serial.print("\t") - #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("t");} - #define SERIAL_BEGIN(x) Serial.begin(x) + #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("\t");} #else + #define SERIAL_BEGIN(x) do {} while (0) #define SERIAL_PRINT(x) do {} while (0) #define SERIAL_PRINTLN(x) do {} while (0) - #define SERIAL_BEGIN(baud) do {} while (0) #define SERIAL_TAB do {} while (0) #define SERIAL_TABS(x) do {} while (0) - #define SERIAL_BEGIN(x) do {} while (0) #endif diff --git a/ColorComposer/SystemTest/include/Debug.h b/ColorComposer/SystemTest/include/Debug.h index ad9c937..caf3ffa 100644 --- a/ColorComposer/SystemTest/include/Debug.h +++ b/ColorComposer/SystemTest/include/Debug.h @@ -2,10 +2,10 @@ * This is a macro for easily enabling or disabling the Serial monitor print statements. * * You can enable serial print debugging by setting - * #define USE_SERIAL 1 + * #define USE_SERIAL * - * Or, you can disable serial print debugging by setting - * #define USE_SERIAL 0 + * Or, you can disable serial print debugging by not setting it + * // #define USE_SERIAL * * In your main code, rather than using Serial.print() or Serial.println(), use their aliases defined below (e.g., SERIAL_PRINTLN()). * @@ -26,18 +26,16 @@ // #define USE_SERIAL -#if USE_SERIAL +#ifdef USE_SERIAL + #define SERIAL_BEGIN(x) Serial.begin(x) #define SERIAL_PRINT(x) Serial.print(x) #define SERIAL_PRINTLN(x) Serial.println(x) - #define SERIAL_BEGIN(baud) Serial.begin(baud) #define SERIAL_TAB Serial.print("\t") - #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("t");} - #define SERIAL_BEGIN(x) Serial.begin(x) + #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("\t");} #else + #define SERIAL_BEGIN(x) do {} while (0) #define SERIAL_PRINT(x) do {} while (0) #define SERIAL_PRINTLN(x) do {} while (0) - #define SERIAL_BEGIN(baud) do {} while (0) #define SERIAL_TAB do {} while (0) #define SERIAL_TABS(x) do {} while (0) - #define SERIAL_BEGIN(x) do {} while (0) #endif diff --git a/ColorComposer/TheChordinator/include/Debug.h b/ColorComposer/TheChordinator/include/Debug.h index ad9c937..caf3ffa 100644 --- a/ColorComposer/TheChordinator/include/Debug.h +++ b/ColorComposer/TheChordinator/include/Debug.h @@ -2,10 +2,10 @@ * This is a macro for easily enabling or disabling the Serial monitor print statements. * * You can enable serial print debugging by setting - * #define USE_SERIAL 1 + * #define USE_SERIAL * - * Or, you can disable serial print debugging by setting - * #define USE_SERIAL 0 + * Or, you can disable serial print debugging by not setting it + * // #define USE_SERIAL * * In your main code, rather than using Serial.print() or Serial.println(), use their aliases defined below (e.g., SERIAL_PRINTLN()). * @@ -26,18 +26,16 @@ // #define USE_SERIAL -#if USE_SERIAL +#ifdef USE_SERIAL + #define SERIAL_BEGIN(x) Serial.begin(x) #define SERIAL_PRINT(x) Serial.print(x) #define SERIAL_PRINTLN(x) Serial.println(x) - #define SERIAL_BEGIN(baud) Serial.begin(baud) #define SERIAL_TAB Serial.print("\t") - #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("t");} - #define SERIAL_BEGIN(x) Serial.begin(x) + #define SERIAL_TABS(x) for (uint8_t i = 0; i < x; i++) {Serial.print("\t");} #else + #define SERIAL_BEGIN(x) do {} while (0) #define SERIAL_PRINT(x) do {} while (0) #define SERIAL_PRINTLN(x) do {} while (0) - #define SERIAL_BEGIN(baud) do {} while (0) #define SERIAL_TAB do {} while (0) #define SERIAL_TABS(x) do {} while (0) - #define SERIAL_BEGIN(x) do {} while (0) #endif diff --git a/IRTurret/shotcount.ino b/IRTurret/shotcount.ino new file mode 100644 index 0000000..9462b6a --- /dev/null +++ b/IRTurret/shotcount.ino @@ -0,0 +1,339 @@ +////////////////////////////////////////////////// +// LICENSE // +////////////////////////////////////////////////// +#pragma region LICENSE +/* + ************************************************************************************ + * MIT License + * + * Copyright (c) 2025 Crunchlabs LLC (IRTurret Control Code) + * Copyright (c) 2020-2022 Armin Joachimsmeyer (IRremote Library) + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + ************************************************************************************ + */ +#pragma endregion LICENSE + +////////////////////////////////////////////////// +// LIBRARIES // +////////////////////////////////////////////////// +#pragma region LIBRARIES + +#include +#include +#include + +#pragma endregion LIBRARIES + +////////////////////////////////////////////////// +// IR CODES // +////////////////////////////////////////////////// +#pragma region IR CODES +/* +** if you want to add other remotes (as long as they're on the same protocol above): +** press the desired button and look for a hex code similar to those below (ex: 0x11) +** then add a new line to #define newCmdName 0x11, +** and add a case to the switch statement like case newCmdName: +** this will let you add new functions to buttons on other remotes! +** the best remotes to try are cheap LED remotes, some TV remotes, and some garage door openers +*/ + +//defines the specific command code for each button on the remote +#define left 0x08 +#define right 0x5A +#define up 0x18 +#define down 0x52 +#define ok 0x1C +#define cmd1 0x45 +#define cmd2 0x46 +#define cmd3 0x47 +#define cmd4 0x44 +#define cmd5 0x40 +#define cmd6 0x43 +#define cmd7 0x07 +#define cmd8 0x15 +#define cmd9 0x09 +#define cmd0 0x19 +#define star 0x16 +#define hash 0x0D + +#define DECODE_NEC //defines the type of IR transmission to decode based on the remote. See IRremote library for examples on how to decode other types of remote + +#pragma endregion IR CODES + +////////////////////////////////////////////////// +// PINS AND PARAMETERS // +////////////////////////////////////////////////// +#pragma region PINS AND PARAMS +//this is where we store global variables! +Servo yawServo; //names the servo responsible for YAW rotation, 360 spin around the base +Servo pitchServo; //names the servo responsible for PITCH rotation, up and down tilt +Servo rollServo; //names the servo responsible for ROLL rotation, spins the barrel to fire darts + +int yawServoVal = 90; //initialize variables to store the current value of each servo +int pitchServoVal = 100; +int rollServoVal = 90; + +int pitchMoveSpeed = 8; //this variable is the angle added to the pitch servo to control how quickly the PITCH servo moves - try values between 3 and 10 +int yawMoveSpeed = 90; //this variable is the speed controller for the continuous movement of the YAW servo motor. It is added or subtracted from the yawStopSpeed, so 0 would mean full speed rotation in one direction, and 180 means full rotation in the other. Try values between 10 and 90; +int yawStopSpeed = 90; //value to stop the yaw motor - keep this at 90 +int rollMoveSpeed = 90; //this variable is the speed controller for the continuous movement of the ROLL servo motor. It is added or subtracted from the rollStopSpeed, so 0 would mean full speed rotation in one direction, and 180 means full rotation in the other. Keep this at 90 for best performance / highest torque from the roll motor when firing. +int rollStopSpeed = 90; //value to stop the roll motor - keep this at 90 + +int yawPrecision = 150; // this variable represents the time in milliseconds that the YAW motor will remain at it's set movement speed. Try values between 50 and 500 to start (500 milliseconds = 1/2 second) +int rollPrecision = 158; // this variable represents the time in milliseconds that the ROLL motor with remain at it's set movement speed. If this ROLL motor is spinning more or less than 1/6th of a rotation when firing a single dart (one call of the fire(); command) you can try adjusting this value down or up slightly, but it should remain around the stock value (160ish) for best results. + +int pitchMax = 150; // this sets the maximum angle of the pitch servo to prevent it from crashing, it should remain below 180, and be greater than the pitchMin +int pitchMin = 33; // this sets the minimum angle of the pitch servo to prevent it from crashing, it should remain above 0, and be less than the pitchMax + +int darts = 6; // assume fully loaded + +void shakeHeadYes(int moves = 3); //function prototypes for shakeHeadYes and No for proper compiling +void shakeHeadNo(int moves = 3); +void fire(int count = 1); +#pragma endregion PINS AND PARAMS + +////////////////////////////////////////////////// +// S E T U P // +////////////////////////////////////////////////// +#pragma region SETUP +void setup() { //this is our setup function - it runs once on start up, and is basically where we get everything "set up" + Serial.begin(9600); // initializes the Serial communication between the computer and the microcontroller + + yawServo.attach(10); //attach YAW servo to pin 10 + pitchServo.attach(11); //attach PITCH servo to pin 11 + rollServo.attach(12); //attach ROLL servo to pin 12 + + // Just to know which program is running on my microcontroller + Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE)); + + // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED + IrReceiver.begin(9, ENABLE_LED_FEEDBACK); + + Serial.print(F("Ready to receive IR signals of protocols: ")); + printActiveIRProtocols(&Serial); + Serial.println(F("at pin 9")); + + homeServos(); //set servo motors to home position +} +#pragma endregion SETUP + +////////////////////////////////////////////////// +// L O O P // +////////////////////////////////////////////////// +#pragma region LOOP + +void loop() { + + /* + * Check if received data is available and if yes, try to decode it. + */ + if (IrReceiver.decode()) { + /* + * Print a short summary of received data + */ + IrReceiver.printIRResultShort(&Serial); + IrReceiver.printIRSendUsage(&Serial); + if (IrReceiver.decodedIRData.protocol == UNKNOWN) { //command garbled or not recognized + Serial.println(F("Received noise or an unknown (or not yet enabled) protocol - if you wish to add this command, define it at the top of the file with the hex code printed below (ex: 0x8)")); + // We have an unknown protocol here, print more info + IrReceiver.printIRResultRawFormatted(&Serial, true); + } + Serial.println(); + + /* + * !!!Important!!! Enable receiving of the next value, + * since receiving has stopped after the end of the current received data packet. + */ + IrReceiver.resume(); // Enable receiving of the next value + /* + * Finally, check the received data and perform actions according to the received command + */ + + switch(IrReceiver.decodedIRData.command) { //this is where the commands are handled + + case up: //pitch up + upMove(1); + break; + + case down: //pitch down + downMove(1); + break; + + case left: //fast counterclockwise rotation + leftMove(1); + break; + + case right: //fast clockwise rotation + rightMove(1); + break; + + case ok: //firing routine + fire(); + break; + + case star: + fire(6); + delay(50); + break; + + case cmd1: + shakeHeadYes(3); + break; + + case cmd2: + shakeHeadNo(3); + break; + + case cmd6: // reload! + darts = 6; + shakeHeadYes(2); + break; + } + } + delay(5); +} + +#pragma endregion LOOP + +////////////////////////////////////////////////// +// FUNCTIONS // +////////////////////////////////////////////////// +#pragma region FUNCTIONS + +void leftMove(int moves) { // function to move left + for (int i = 0; i < moves; i++) { + yawServo.write(yawStopSpeed + yawMoveSpeed); // adding the servo speed = 180 (full counterclockwise rotation speed) + delay(yawPrecision); // stay rotating for a certain number of milliseconds + yawServo.write(yawStopSpeed); // stop rotating + delay(5); //delay for smoothness + Serial.println(F("LEFT")); + } + +} + +void rightMove(int moves) { // function to move right + for (int i = 0; i < moves; i++) { + yawServo.write(yawStopSpeed - yawMoveSpeed); //subtracting the servo speed = 0 (full clockwise rotation speed) + delay(yawPrecision); + yawServo.write(yawStopSpeed); + delay(5); + Serial.println(F("RIGHT")); + } +} + +void upMove(int moves) { // function to tilt up + for (int i = 0; i < moves; i++) { + if((pitchServoVal+pitchMoveSpeed) < pitchMax) { //make sure the servo is within rotation limits (less than 150 degrees by default) + pitchServoVal = pitchServoVal + pitchMoveSpeed; //increment the current angle and update + pitchServo.write(pitchServoVal); + delay(50); + Serial.println(F("UP")); + } + } +} + +void downMove (int moves) { // function to tilt down + for (int i = 0; i < moves; i++) { + if((pitchServoVal-pitchMoveSpeed) > pitchMin) { //make sure the servo is within rotation limits (greater than 35 degrees by default) + pitchServoVal = pitchServoVal - pitchMoveSpeed; //decrement the current angle and update + pitchServo.write(pitchServoVal); + delay(50); + Serial.println(F("DOWN")); + } + } +} + +void fire(int count) { //function for firing a single dart + int shots = constrain(count, 0, darts); // can't shoot more than you have + if (shots == 0) { + shakeHeadNo(2); + return; // nothing to shoot! + } + rollServo.write(rollStopSpeed + rollMoveSpeed); //start rotating the servo + delay(rollPrecision * shots); //time for approximately 60 degrees of rotation + rollServo.write(rollStopSpeed); //stop rotating the servo + delay(5); //delay for smoothness + Serial.print(F("FIRING ")); + if (shots >= darts) Serial.print(F("ALL ")); + Serial.println(shots); + darts -= shots; +} + +void homeServos() { // sends servos to home positions + yawServo.write(yawStopSpeed); //setup YAW servo to be STOPPED (90) + delay(20); + rollServo.write(rollStopSpeed); //setup ROLL servo to be STOPPED (90) + delay(100); + pitchServoVal = 100; //set PITCH servo to 100 degree position + pitchServo.write(pitchServoVal); + delay(100); + Serial.println(F("HOMING")); +} + +void shakeHeadYes(int moves = 3) { //sets the default number of nods to 3, but you can pass in whatever number of nods you want + Serial.println(F("YES")); + + if ((pitchMax - pitchServoVal) < 15) { + pitchServoVal = pitchServoVal - 15; + } else if ((pitchServoVal - pitchMin) < 15) { + pitchServoVal = pitchServoVal + 15; + } + pitchServo.write(pitchServoVal); + + int startAngle = pitchServoVal; // Current position of the pitch servo + // int lastAngle = pitchServoVal; never used ?? + int nodAngle = startAngle + 15; // Angle for nodding motion + + for (int i = 0; i < moves; i++) { // Repeat nodding motion three times + // Nod up + for (int angle = startAngle; angle <= nodAngle; angle++) { + pitchServo.write(angle); + delay(7); // Adjust delay for smoother motion + } + delay(50); // Pause at nodding position + // Nod down + for (int angle = nodAngle; angle >= startAngle; angle--) { + pitchServo.write(angle); + delay(7); // Adjust delay for smoother motion + } + delay(50); // Pause at starting position + } +} + +void shakeHeadNo(int moves = 3) { + Serial.println(F("NO")); + + for (int i = 0; i < moves; i++) { // Repeat nodding motion three times + // rotate right, stop, then rotate left, stop + yawServo.write(140); + delay(190); // Adjust delay for smoother motion + yawServo.write(yawStopSpeed); + delay(50); + yawServo.write(40); + delay(190); // Adjust delay for smoother motion + yawServo.write(yawStopSpeed); + delay(50); // Pause at starting position + } +} +#pragma endregion FUNCTIONS + +////////////////////////////////////////////////// +// END CODE // +////////////////////////////////////////////////// diff --git a/IRTurret/shotdisplay.ino b/IRTurret/shotdisplay.ino new file mode 100644 index 0000000..2055294 --- /dev/null +++ b/IRTurret/shotdisplay.ino @@ -0,0 +1,368 @@ +////////////////////////////////////////////////// +// LICENSE // +////////////////////////////////////////////////// +#pragma region LICENSE +/* + ************************************************************************************ + * MIT License + * + * Copyright (c) 2025 Crunchlabs LLC (IRTurret Control Code) + * Copyright (c) 2020-2022 Armin Joachimsmeyer (IRremote Library) + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + ************************************************************************************ + */ +#pragma endregion LICENSE + +////////////////////////////////////////////////// +// LIBRARIES // +////////////////////////////////////////////////// +#pragma region LIBRARIES + +#include +#include +#include +#include + +#pragma endregion LIBRARIES + +////////////////////////////////////////////////// +// IR CODES // +////////////////////////////////////////////////// +#pragma region IR CODES +/* +** if you want to add other remotes (as long as they're on the same protocol above): +** press the desired button and look for a hex code similar to those below (ex: 0x11) +** then add a new line to #define newCmdName 0x11, +** and add a case to the switch statement like case newCmdName: +** this will let you add new functions to buttons on other remotes! +** the best remotes to try are cheap LED remotes, some TV remotes, and some garage door openers +*/ + +//defines the specific command code for each button on the remote +#define left 0x08 +#define right 0x5A +#define up 0x18 +#define down 0x52 +#define ok 0x1C +#define cmd1 0x45 +#define cmd2 0x46 +#define cmd3 0x47 +#define cmd4 0x44 +#define cmd5 0x40 +#define cmd6 0x43 +#define cmd7 0x07 +#define cmd8 0x15 +#define cmd9 0x09 +#define cmd0 0x19 +#define star 0x16 +#define hash 0x0D + +#define DECODE_NEC //defines the type of IR transmission to decode based on the remote. See IRremote library for examples on how to decode other types of remote + +#pragma endregion IR CODES + +////////////////////////////////////////////////// +// PINS AND PARAMETERS // +////////////////////////////////////////////////// +#pragma region PINS AND PARAMS +//this is where we store global variables! +Servo yawServo; //names the servo responsible for YAW rotation, 360 spin around the base +Servo pitchServo; //names the servo responsible for PITCH rotation, up and down tilt +Servo rollServo; //names the servo responsible for ROLL rotation, spins the barrel to fire darts + +LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display + +int yawServoVal = 90; //initialize variables to store the current value of each servo +int pitchServoVal = 100; +int rollServoVal = 90; + +int pitchMoveSpeed = 8; //this variable is the angle added to the pitch servo to control how quickly the PITCH servo moves - try values between 3 and 10 +int yawMoveSpeed = 90; //this variable is the speed controller for the continuous movement of the YAW servo motor. It is added or subtracted from the yawStopSpeed, so 0 would mean full speed rotation in one direction, and 180 means full rotation in the other. Try values between 10 and 90; +int yawStopSpeed = 90; //value to stop the yaw motor - keep this at 90 +int rollMoveSpeed = 90; //this variable is the speed controller for the continuous movement of the ROLL servo motor. It is added or subtracted from the rollStopSpeed, so 0 would mean full speed rotation in one direction, and 180 means full rotation in the other. Keep this at 90 for best performance / highest torque from the roll motor when firing. +int rollStopSpeed = 90; //value to stop the roll motor - keep this at 90 + +int yawPrecision = 150; // this variable represents the time in milliseconds that the YAW motor will remain at it's set movement speed. Try values between 50 and 500 to start (500 milliseconds = 1/2 second) +int rollPrecision = 158; // this variable represents the time in milliseconds that the ROLL motor with remain at it's set movement speed. If this ROLL motor is spinning more or less than 1/6th of a rotation when firing a single dart (one call of the fire(); command) you can try adjusting this value down or up slightly, but it should remain around the stock value (160ish) for best results. + +int pitchMax = 150; // this sets the maximum angle of the pitch servo to prevent it from crashing, it should remain below 180, and be greater than the pitchMin +int pitchMin = 33; // this sets the minimum angle of the pitch servo to prevent it from crashing, it should remain above 0, and be less than the pitchMax + +int darts = 6; // assume fully loaded +int fired = 0; // none shot yet + +void shakeHeadYes(int moves = 3); //function prototypes for shakeHeadYes and No for proper compiling +void shakeHeadNo(int moves = 3); +void fire(int count = 1); +#pragma endregion PINS AND PARAMS + +////////////////////////////////////////////////// +// S E T U P // +////////////////////////////////////////////////// +#pragma region SETUP +void setup() { //this is our setup function - it runs once on start up, and is basically where we get everything "set up" + + lcd.init(); // initialize the LCD + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print(F("Hack Pack Turret")); + showdarts(); // display count and remaining + + Serial.begin(9600); // initializes the Serial communication between the computer and the microcontroller + + yawServo.attach(10); //attach YAW servo to pin 10 + pitchServo.attach(11); //attach PITCH servo to pin 11 + rollServo.attach(12); //attach ROLL servo to pin 12 + + // Just to know which program is running on my microcontroller + Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE)); + + // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED + IrReceiver.begin(9, ENABLE_LED_FEEDBACK); + + Serial.print(F("Ready to receive IR signals of protocols: ")); + printActiveIRProtocols(&Serial); + Serial.println(F("at pin 9")); + + homeServos(); //set servo motors to home position +} +#pragma endregion SETUP + +////////////////////////////////////////////////// +// L O O P // +////////////////////////////////////////////////// +#pragma region LOOP + +void loop() { + + /* + * Check if received data is available and if yes, try to decode it. + */ + if (IrReceiver.decode()) { + /* + * Print a short summary of received data + */ + IrReceiver.printIRResultShort(&Serial); + IrReceiver.printIRSendUsage(&Serial); + if (IrReceiver.decodedIRData.protocol == UNKNOWN) { //command garbled or not recognized + Serial.println(F("Received noise or an unknown (or not yet enabled) protocol - if you wish to add this command, define it at the top of the file with the hex code printed below (ex: 0x8)")); + // We have an unknown protocol here, print more info + IrReceiver.printIRResultRawFormatted(&Serial, true); + } + Serial.println(); + + /* + * !!!Important!!! Enable receiving of the next value, + * since receiving has stopped after the end of the current received data packet. + */ + IrReceiver.resume(); // Enable receiving of the next value + /* + * Finally, check the received data and perform actions according to the received command + */ + + switch(IrReceiver.decodedIRData.command) { //this is where the commands are handled + + case up: //pitch up + upMove(1); + break; + + case down: //pitch down + downMove(1); + break; + + case left: //fast counterclockwise rotation + leftMove(1); + break; + + case right: //fast clockwise rotation + rightMove(1); + break; + + case ok: //firing routine + fire(); + break; + + case star: + fire(6); + delay(50); + break; + + case cmd1: + shakeHeadYes(3); + break; + + case cmd2: + shakeHeadNo(3); + break; + + case cmd6: // reload! + darts = 6; + //shakeHeadYes(2); + showdarts(); + break; + } + } + delay(5); +} + +#pragma endregion LOOP + +////////////////////////////////////////////////// +// FUNCTIONS // +////////////////////////////////////////////////// +#pragma region FUNCTIONS + +void leftMove(int moves) { // function to move left + for (int i = 0; i < moves; i++) { + yawServo.write(yawStopSpeed + yawMoveSpeed); // adding the servo speed = 180 (full counterclockwise rotation speed) + delay(yawPrecision); // stay rotating for a certain number of milliseconds + yawServo.write(yawStopSpeed); // stop rotating + delay(5); //delay for smoothness + Serial.println(F("LEFT")); + } + +} + +void rightMove(int moves) { // function to move right + for (int i = 0; i < moves; i++) { + yawServo.write(yawStopSpeed - yawMoveSpeed); //subtracting the servo speed = 0 (full clockwise rotation speed) + delay(yawPrecision); + yawServo.write(yawStopSpeed); + delay(5); + Serial.println(F("RIGHT")); + } +} + +void upMove(int moves) { // function to tilt up + for (int i = 0; i < moves; i++) { + if((pitchServoVal+pitchMoveSpeed) < pitchMax) { //make sure the servo is within rotation limits (less than 150 degrees by default) + pitchServoVal = pitchServoVal + pitchMoveSpeed; //increment the current angle and update + pitchServo.write(pitchServoVal); + delay(50); + Serial.println(F("UP")); + } + } +} + +void downMove (int moves) { // function to tilt down + for (int i = 0; i < moves; i++) { + if((pitchServoVal-pitchMoveSpeed) > pitchMin) { //make sure the servo is within rotation limits (greater than 35 degrees by default) + pitchServoVal = pitchServoVal - pitchMoveSpeed; //decrement the current angle and update + pitchServo.write(pitchServoVal); + delay(50); + Serial.println(F("DOWN")); + } + } +} + +void fire(int count) { //function for firing a single dart + int shots = constrain(count, 0, darts); // can't shoot more than you have + if (shots == 0) { + shakeHeadNo(2); + return; // nothing to shoot! + } + rollServo.write(rollStopSpeed + rollMoveSpeed); //start rotating the servo + delay(rollPrecision * shots); //time for approximately 60 degrees of rotation + rollServo.write(rollStopSpeed); //stop rotating the servo + delay(5); //delay for smoothness + Serial.print(F("FIRING ")); + if (shots >= darts) Serial.print(F("ALL ")); + Serial.println(shots); + darts -= shots; + fired += constrain(shots, 0, 999-fired); // can't display more than 999 + showdarts(); +} + +void homeServos() { // sends servos to home positions + yawServo.write(yawStopSpeed); //setup YAW servo to be STOPPED (90) + delay(20); + rollServo.write(rollStopSpeed); //setup ROLL servo to be STOPPED (90) + delay(100); + pitchServoVal = 100; //set PITCH servo to 100 degree position + pitchServo.write(pitchServoVal); + delay(100); + Serial.println(F("HOMING")); +} + +void shakeHeadYes(int moves = 3) { //sets the default number of nods to 3, but you can pass in whatever number of nods you want + Serial.println(F("YES")); + + if ((pitchMax - pitchServoVal) < 15) { + pitchServoVal = pitchServoVal - 15; + } else if ((pitchServoVal - pitchMin) < 15) { + pitchServoVal = pitchServoVal + 15; + } + pitchServo.write(pitchServoVal); + + int startAngle = pitchServoVal; // Current position of the pitch servo + // int lastAngle = pitchServoVal; never used ?? + int nodAngle = startAngle + 15; // Angle for nodding motion + + for (int i = 0; i < moves; i++) { // Repeat nodding motion three times + // Nod up + for (int angle = startAngle; angle <= nodAngle; angle++) { + pitchServo.write(angle); + delay(7); // Adjust delay for smoother motion + } + delay(50); // Pause at nodding position + // Nod down + for (int angle = nodAngle; angle >= startAngle; angle--) { + pitchServo.write(angle); + delay(7); // Adjust delay for smoother motion + } + delay(50); // Pause at starting position + } +} + +void shakeHeadNo(int moves = 3) { + Serial.println(F("NO")); + + for (int i = 0; i < moves; i++) { // Repeat nodding motion three times + // rotate right, stop, then rotate left, stop + yawServo.write(140); + delay(190); // Adjust delay for smoother motion + yawServo.write(yawStopSpeed); + delay(50); + yawServo.write(40); + delay(190); // Adjust delay for smoother motion + yawServo.write(yawStopSpeed); + delay(50); // Pause at starting position + } +} + +void showdarts() { + lcd.setCursor(0, 1); + if (fired < 100) + lcd.print(F(" ")); + if (fired < 10) + lcd.print(F(" ")); + lcd.print(fired); + lcd.print(F(" Fired ")); + if (darts > 0) { + lcd.print(darts); + lcd.print(F(" Left")); + } else + lcd.print(F("RELOAD")); +} +#pragma endregion FUNCTIONS + +////////////////////////////////////////////////// +// END CODE // +//////////////////////////////////////////////////