//øøøøø[ Begin: IDENTIFICATION DIVISION ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// // // PROGRAM-ID: IR_stepper_motor_v0.1 // Date: 05/12/2020 // Environment: Arduino IDE v1.8.12 on Windows v10.0.18363 Build 18363 x64 // Author: Casey Gilbertson a.k.a. itsCaseyDambit // Contributors: Tom Igoe (his name was on the original sketch, so, here it is, like it's supposed to be (hint hint)) // Inspired by: The DroneBot Workshop (thanks always, Bill!) https://www.youtube.com/channel/UCzml9bXoEM0itbcE96CB03w and Subscribe! // Join the DroneBot Workshop Forum. A great place to share ideas and learn. https://wordpress-1177183-4121410.cloudwaysapps.com/ // // Forward: If you're a beginner and are learning about the map() function, this is a great opportunity to test the waters and see how // different map() settings not only affect the way the potentiometer re-acts, but also (and more importantly), how the different // map() settings affects the dc motor's performance. https://www.arduino.cc/reference/en/language/functions/math/map/ // https://www.best-microcontroller-projects.com/arduino-map.html // // My naming conventions I use are simple; you can practically understand the programming logic just by reading the code. // // If you can think of ways to improve this sketch, that's exactly what it's here for. Experiment, modify, tinker, open your // imagination. Control the motor speed with the IR remote control instead of the speed pot. The possibilities with Arduino // are nearly endless. // // This sketch is documented as if the next person modifying the thing has no idea what's going on - // like it's supposed to be (hint hint). Comments carry concepts that code simply can't. // // Let's get smarter... // // Purpose: In the original sketch - Stepper-Demo1.ino - they used various-length loops to spin the geared drive shaft of the 28BYJ-48 // motor at various, predetermined speeds in clockwise/counter-clockwise rotations. // // In this sketch, we're controlling the 28BYJ-48 motor's rotational direction via initialization of the variable named thisDir, // and we control the speed of the motor with a breadboard-friendly B103 potentiometer. This code is designed for expandability. // Build onto this sketch to suit your needs. // // You'll need to power the motor through an external 5vDC supply of some nature - the breadboard-friendly 3.3v/5v power supply // provided in every Arduino Starter Kit is best suited. Use the UNO board to power everything else like the speed pot, but not // the dc motor - excessive current draw can damage the UNO board. // // The best thing about this sketch is the information that a previous contributor supplied regarding the 28BYJ-48's data sheet // specs (saved me the trouble; regards, Tom). I used the original Stepper-Demo1.ino file and sliced it into tiny little pieces // until there were only three lines of code remaining in the loop(). I've now got three lines of code down to two lines of code. // TWO LINES OF CODE to run a dc motor using a speed pot. Not much to clean up, there. // // The two lines of code run the motor in one direction continuously for the entire step cycle (2,048-armature revolutions // equals one drive shaft revolution)...a perfect place to start. I then added-in potentiometer analogRead() and map() function // calls to control the motor's speed. I figured as long as we've gone this far, why not? It's all achademic (and really simple code). // // Points of interest: in the global variables, when we create an instance of 'Stepper,' it's important to specify which Arduino // pins are used for the motor coils. The pins we're using are 8, 9, 10, and 11, and those pins are connected to the ULN2003 Motor // Driver's terminals: In1, In2, In3, In4. // // Below, when we declare the instance of Stepper myStepper() in the global variables, the Arduino pin numbers are // declared in a sequence of: 1-3-2-4 (for proper motor-coil step sequencing). So... // // in this instance, we use an Arduino pin sequence of: 8, 10, 9, 11 ... // // Stepper myStepper( CYCLE_STEPS, 8, 10, 9, 11 ); (Except, I use hex) // // That's an important detail we don't want to miss if we expect the motor to run correctly. // // Sketch Logic: There are three elements in this code that are the heartbeat of the logic: // // const float CW = -TOTAL_STEPS; // a negative value makes the motor run clockwise (CW). (we could use TOTAL_STEPS * -0x01; but why? lol) // const float CCW = +TOTAL_STEPS; // a positive value makes the motor run counter-clockwise (CCW) // float thisDir = CW; // initialize the rotation to clockwise (CW) - the two possible values for thisDir are: CW = -TOTAL_STEPS and CCW = +TOTAL_STEPS // // These three elements determine which direction the motor will rotate. I've placed (+) positive and (-) negative signs // in front of the two variable's names so that we know the state of the value as positive or negative (that's more of a // pseudocode thing - it makes it easier for the reader to understand). The most important fact is that the CW value is NEGATIVE, // and the CCW value is POSITIVE. // // The value of TOTAL_STEPS is predetermined through an equation in the variable's definition statement: TOTAL_STEPS = CYCLE_STEPS * GEAR_REDUCT; // so, all we're doing is using TOTAL_STEPS as either a positive or negative value, and we're storing that value in thisDir. // In that, the value stored in thisDir will be either +0x800 or -0x800. Period. // // Interesting note: the code I've just been referring to is both important and unnecessary. Wrap your head around THAT! lol // // Here's the thing: we know the values of CYCLE_STEPS (0x20) and GEAR_REDUCT (0x40); they are constants. In theory, we could bypass // using the equation CYCLE_STEPS times GEAR_REDUCT for a product of 0x800; that, too, would be a constant. So, why // don't we simply use a value of +0x800 or -0x800 to determine which direction we want the motor to spin? We could eliminate two // two variables and an equation from the sketch. One word: upgradeablity. // // Let's say you have motor other than the 28BYJ-48 Unipolar dc motor used in this sketch. You've checked the data sheet of the new motor, // and the specs for CYCLE_STEPS and GEAR_REDUCT are not the same. Cool. Simply plug the new values into CYCLE_STEPS and GEAR_REDUCT, // and your problems are solved. Changing the value of two variables (constants, actually) changes the sketch just enough to use a // different motor. What a time saver THAT is. We don't have to write code twice? #pffft. Sign me up. // // Tests: At compile time... // // Sketch uses 2194 bytes (6%) of program storage space. Maximum is 32256 bytes. // Global variables use 35 bytes (1%) of dynamic memory, leaving 2013 bytes for local variables. Maximum is 2048 bytes. // // Not bad at all. We're controlling a dc motor with a driver and a speed pot, and we used 1% of the dynamic memory. ONE PERCENT! // // BOL: 1 ea. Arduino UNO board // 1 ea. 28BYJ-48 Unipolar dc motor // 1 ea. ULN2003 dc motor driver board // 1 ea. B103 potentiometer // 1 ea. 3.3v/5v power supply (don't power the dc motor through the UNO board: current draw is too high - it burns-up the UNO) // 10 ea. M-M jumper leads should be fine // 1 ea. USB Type-A male to Type-B male cable // // Notes: This sketch is a great learning tool, and I hope in some manner we now better understand the 28BYJ-48 Unipolar dc motor, // its internal operations, and how to control the little bugger. // // Take Care! // No animals were harmed in the making of this file. // // Copyright©: This file is released to public domain. // //øøøøø[ End: IDENTIFICATION DIVISION ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø we now pause, as cobol coders chuckle. //øøøøø[ Begin: Global variables ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø moving on... #include // include the Arduino Stepper Library for stepper motor control method definitions const float CYCLE_STEPS = 0x20; // <<- the internal motor steps per 360º armature rotation cycle - a.k.a. the Step Angle for this model of 28BYJ-48 Unipolar motor const float GEAR_REDUCT = 0x40; // <<- the internal gear-reduction ratio for this model of 28BYJ-48 const float TOTAL_STEPS = // to get the TOTAL_STEPS to acheive 360º drive shaft rotation ( 0x20 = 32 ) (and this demonstrstes how hex numbers used in CYCLE_STEPS * // <<- multiply CYCLE_STEPS by GEAR_REDUCT ( *0x40 = *64 ) coding are WAY EASIER to use than decimal numbers) GEAR_REDUCT; // <<- to find the TOTAL_STEPS per 360º of drive shaft rotation ------- ----- // ( 0x800 = 2,048 ) 2,048 360º armature rotations of for every ONE geared, const float CW = -TOTAL_STEPS; // a negative value makes the motor run clockwise (CW) 360º drive-shaft rotation (dats a whole lotta torque!) const float CCW = +TOTAL_STEPS; // a positive value makes the motor run counter-clockwise (CCW) float thisDir = CW; // YOU must initialize the value of thisDIR to CW or CCW BEFORE you run the sketch. It's your call: which direction do you want the motor to spin? const int SPEEDPOT_PIN = A0; // the motor's analog speed-pot pin. we could simply use the value of A0 in the code, but, this makes the code easier to read and understand Stepper myStepper( // create an instance of 'Stepper' to run one 28BYJ-48 Unipolar Stepper motor with a ULN2003 driver CYCLE_STEPS, // <<- declares the number of interal steps the motor uses in one 360º cycle 0x08, 0x0a, 0x09, 0x0b ); // <<- and which Arduino digital pins that will be used to fire the ULN2003 driver, which then fires the 28BYJ-48's motor coils //øøøøø[ End: Global variables ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// //øøøøø[ Begin functiion: setup() ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// void setup() { pinMode( SPEEDPOT_PIN, INPUT ); // set the speed-pot pin mode as input. the Arduino UNO can determine if an analog pin is input or output all on its own, and this line of code // could be removed, but, I like to let the compiler know what's going on, and it make this code as clear as possible, so, I state the pin mode. } //øøøøø[ End functiion: setup() ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// //øøøøø[ Begin functiion: loop() ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// void loop() { myStepper.setSpeed( map( analogRead( SPEEDPOT_PIN ), 0x00, 0x3ff, 0x7f, 0x3ff ) ); // read the speed pot, map() the value, and set the motor's speed myStepper.step( ( thisDir / GEAR_REDUCT ) ); // run one internal step angle of the motor } // lather, rinse, and repeat the loop() endlessly //øøøøø[ End functiion: loop() ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// //øøøøø[ End of file ]øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø// //