├── .github └── workflows │ └── build.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── RELEASE.md ├── examples ├── ATtiny85-Test │ └── ATtiny85-Test.ino ├── LaserGimbal.png ├── LaserGimbal │ └── LaserGimbal.ino ├── README.md ├── RobotArm │ ├── README.md │ └── RobotArm.ino ├── RoboticArm.png ├── Stepper28BYJ-48.png └── TinyStepper-Test │ └── TinyStepper-Test.ino ├── keywords.txt ├── library.json ├── library.properties └── src ├── TinyStepper.cpp └── TinyStepper.h /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Test Arduino Library 2 | name: Build Test 3 | 4 | # The workflow will run on every push and pull request to the repository 5 | on: 6 | - push 7 | - pull_request 8 | 9 | jobs: 10 | compile-sketch: 11 | runs-on: ubuntu-latest 12 | 13 | # Boards to test 14 | strategy: 15 | matrix: 16 | fqbn: 17 | - arduino:avr:uno 18 | 19 | steps: 20 | # This step makes the contents of the repository available to the workflow 21 | - name: Checkout repository 22 | uses: actions/checkout@v2 23 | 24 | # For more information: https://github.com/arduino/compile-sketches#readme 25 | - name: Compile example sketches 26 | uses: arduino/compile-sketches@v1 27 | with: 28 | # Board type to test 29 | fqbn: ${{ matrix.fqbn }} 30 | # The default is to compile for the Arduino Uno board. If you want to compile for other boards, use the `fqbn` input. 31 | sketch-paths: | 32 | # Search all files under the examples path in the repository for sketches and compile them. 33 | # This is formatted as a YAML list, which makes it possible to have multiple sketch paths if needed. 34 | - ./examples 35 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Local 35 | .DS_Store 36 | 37 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | before_install: 3 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" 4 | - sleep 3 5 | - export DISPLAY=:1.0 6 | - wget https://downloads.arduino.cc/arduino-1.8.12-linux64.tar.xz 7 | - tar xf arduino-1.8.12-linux64.tar.xz 8 | - sudo mv arduino-1.8.12 /usr/local/share/arduino 9 | - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino 10 | - sudo ln -s /usr/local/share/arduino $HOME/Arduino 11 | install: 12 | - ln -s $PWD/src/ /usr/local/share/arduino/libraries/TinyStepper 13 | script: 14 | - arduino --verify --board arduino:avr:uno --pref sketchbook.path="$PWD" $PWD/examples/TinyStepper-Test/TinyStepper-Test.ino 15 | notifications: 16 | email: 17 | on_success: change 18 | on_failure: change 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jason Cox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tiny Stepper # 2 | 3 | [![arduino-library-badge](https://www.ardu-badge.com/badge/TinyStepper.svg?)](https://www.ardu-badge.com/TinyStepper) 4 | [![Build Test](https://github.com/jasonacox/TinyStepper/actions/workflows/build.yml/badge.svg)](https://github.com/jasonacox/TinyStepper/actions/workflows/build.yml) 5 | 6 | Arduino library to drive stepper motors. Small and easy to use. 7 | 8 | ## Description ## 9 | 10 | Simple library to drive a 4-phase stepper motor using simple Move(), AccelMove() and Disable() functions. Works well with 28BYJ-48 stepper motor and UNL2003 module. Focus is on controlling steppers with basic Move(x) commands where x is positive or negative value (in degrees). Uses half-step for more torque and smoother motion. 11 | 12 | ## Hardware ## 13 | 14 | A Stepper Motor is typically driven by a ULN2003A which provides an array of seven NPN Darlington transistors capable of 500 mA, 50 V output, great for driving inductive loads like a motor. 15 | 16 | ![28BYJ-48](examples/Stepper28BYJ-48.png) 17 | 18 | The stepper motor has 4 different position coils, ABCD. In half step mode, you energize the adjacent coil before disengaging the previous coil. The transition steps would be these 8 patterns: A, AB, B, BC, C, CD, D, DA: 19 | 20 | ```text 21 | Phase ABCD Coils 22 | 0 1000 A 23 | 1 1100 AB 24 | 2 0100 B 25 | 3 0110 BC 26 | 4 0010 C 27 | 5 0011 CD 28 | 6 0001 D 29 | 7 1001 A D 30 | ``` 31 | 32 | The ABCD coils map to IN1, IN2, IN3, and IN4 that will be connected to the Arduino digital outputs. 33 | 34 | Power Note: You should not drive the stepper motor power with the Arduino. The power to the UNL2003 module should come from the main power adapter that also feeds the Arduino. 35 | 36 | ## Installation ## 37 | 38 | This library is available via the Arduino IDE. Install this library via `Tools`, `Manage Libraries`, search for "TinyStepper" and click `Install`. 39 | 40 | You can also install the latest version manually by cloning this repo into your Arduino library folder (e.g. `~/Documents/Arduino/libraries`). 41 | 42 | ## Usage ## 43 | 44 | The library provides a single class named TinyStepper with the following functions: 45 | 46 | * `Move` - Move the stepper motor specified in degrees (positive or negative) 47 | * `AccelMove` - Move the stepper motor specified in degrees but accelerate and decelerate. 48 | * `Enable` - Enable/lock the stepper motor 49 | * `Disable` - Disable/unlock the stepper motor (free spin) 50 | 51 | 52 | ## Example Code ## 53 | 54 | ```cpp 55 | #include 56 | 57 | // Define Arduino Pin Outputs 58 | #define IN1 8 59 | #define IN2 9 60 | #define IN3 10 61 | #define IN4 11 62 | #define HALFSTEPS 4096 // Number of half-steps for a full rotation 63 | 64 | // Init the TinyStepper Class 65 | TinyStepper stepper(HALFSTEPS, IN1, IN2, IN3, IN4); 66 | 67 | void setup() 68 | { 69 | Serial.begin(38400); 70 | stepper.Enable(); 71 | delay(1000); 72 | } 73 | 74 | void loop() { 75 | // Random back and forth 76 | Serial.println("Random Test"); 77 | stepper.Move(45); 78 | stepper.Move(-90); 79 | stepper.Move(120); 80 | stepper.Move(-15); 81 | stepper.Move(30); 82 | stepper.Move(-300); 83 | stepper.Move(600); 84 | stepper.Move(-100); 85 | delay(2000); 86 | 87 | // Accelerate/decelerate 360 full rotation - both directions 88 | Serial.println("Full Rotation"); 89 | stepper.AccelMove(360); 90 | stepper.AccelMove(-360, 1, 10); 91 | delay(2000); 92 | } 93 | ``` 94 | 95 | Refer to [TinyStepper.h](src/TinyStepper.h) for information on available functions. See also [Examples](examples) for more demonstration. 96 | 97 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Notes for TinyStepper 2 | 3 | ## v1.2.0 - Enable Fix 4 | 5 | - Moved pin initialization to `Enable()` function and added `Begin()` as alias. 6 | - Either `Enable()` or `Begin()` should be called at least once in `setup()` to initialize pins and stepper motors. 7 | 8 | ## v1.1.0 - Example Sketches 9 | 10 | Updated and added example Arduino sketches: 11 | 12 | - TinyStepper-Test - Basic Test 13 | - ATtiny85 Test - Simple single stepper example tested with an ATtiny85 14 | - Laser Gimbal - A two stepper gimbal for a laser pointer 15 | - Robotic Arm - A three stepper robotic arm 16 | 17 | ## v1.0.0 18 | 19 | - Initial Release. 20 | -------------------------------------------------------------------------------- /examples/ATtiny85-Test/ATtiny85-Test.ino: -------------------------------------------------------------------------------- 1 | /* 2 | TinyStepper - Stepper Motor Test using ATtiny85 3 | by Jason A. Cox - @jasonacox 4 | 5 | Date: 1 August 2020 6 | 7 | Tested with ATtiny85 with ATtinyCore core at 8 MHz (internal) 8 | */ 9 | 10 | #include 11 | 12 | // Define ATtiny85 Pin Outputs to to the ULN2003 Darlington Array to drive a 28BYJ-48 Stepper Motor 13 | #define IN1 1 14 | #define IN2 2 15 | #define IN3 3 16 | #define IN4 4 17 | 18 | #define HALFSTEPS 4096 // Number of half-steps for a full rotation 19 | 20 | // Initialize the TinyStepper Class 21 | TinyStepper stepper(HALFSTEPS, IN1, IN2, IN3, IN4); 22 | 23 | void setup() 24 | { 25 | stepper.Enable(); 26 | delay(1000); 27 | } 28 | 29 | void loop() { 30 | 31 | // Random back and forth 32 | stepper.Move(45); 33 | stepper.Move(-90); 34 | stepper.Move(120); 35 | stepper.Move(-15); 36 | stepper.Move(30); 37 | stepper.Move(-300); 38 | stepper.Move(600); 39 | stepper.Move(-100); 40 | delay(2000); 41 | 42 | // Accelerate/decelerate 360 full rotation - both directions 43 | stepper.AccelMove(360); 44 | stepper.AccelMove(-360, 1, 10); 45 | delay(2000); 46 | } 47 | -------------------------------------------------------------------------------- /examples/LaserGimbal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonacox/TinyStepper/349c6b5c5f4271e31a9d93dbd129f3ec82e9567c/examples/LaserGimbal.png -------------------------------------------------------------------------------- /examples/LaserGimbal/LaserGimbal.ino: -------------------------------------------------------------------------------- 1 | /* 2 | TinyStepper - 2 Stepper Motor Laser Gimbal 3 | by Jason A. Cox - @jasonacox 4 | Date: 19 July 2020 5 | 6 | Laser Gimbal with 2 Stepper Motors based on Thingiverse project: https://www.thingiverse.com/thing:794786 7 | Test cycles each stepper then draws a circle with the laser pointer. Switches allow users to move the 8 | center of the circle (up/down/left/right). 9 | 10 | Arduino Microcontroller (e.g. Uno) 11 | 2 x 28BYJ-48 Stepper Motors 12 | 2 x ULN2003 Driver Board 13 | 1 x Laser (e.g. 5V 650nm 5mW Red Dot Diode Laser) 14 | 4 x Microswitches 15 | 4 x 61k Ohm Resistors (pull up resistor for switches) 16 | 5V Power Supply (do not power steppers with Arduino) 17 | 18 | */ 19 | 20 | #include 21 | 22 | // Number of half-steps for a full rotation 23 | #define HALFSTEPS 4096 24 | 25 | #define FACTOR 5 // Size of circle 26 | #define STEPWAIT 2 // Time to wait for motor to move between steps (-Speed vs Smooth+) 27 | #define RESOLUTION 10 // Increase to smooth circle by staggering stepper updates 28 | 29 | // Motion control microswitches 30 | #define UP1 2 31 | #define DOWN1 3 32 | #define UP2 12 33 | #define DOWN2 13 34 | 35 | // Arduino Pin Outputs to to the ULN2003 for the 28BYJ-48 Stepper Motors 36 | // IN1 IN2 IN3 IN4 37 | TinyStepper stepper1(HALFSTEPS, 8, 9, 10, 11); 38 | TinyStepper stepper2(HALFSTEPS, 4, 5, 6, 7); 39 | 40 | // Global variables 41 | float dx; 42 | float dy; 43 | float t; 44 | int buttondown = 0; 45 | 46 | void setup() 47 | { 48 | Serial.begin(38400); 49 | 50 | stepper1.Enable(); 51 | stepper2.Enable(); 52 | delay(1000); 53 | 54 | pinMode(UP1, INPUT); 55 | pinMode(DOWN1, INPUT); 56 | 57 | pinMode(UP2, INPUT); 58 | pinMode(DOWN2, INPUT); 59 | 60 | Serial.println("Stepper 1 Motion Test"); 61 | stepper1.AccelMove(20); 62 | stepper1.AccelMove(-20); 63 | 64 | Serial.println("Stepper 2 Motion Test"); 65 | stepper2.AccelMove(20); 66 | stepper2.AccelMove(-20); 67 | 68 | dx = 0.0; 69 | dy = 0.0; 70 | t = 0.0; 71 | 72 | Serial.println("Starting Circle Test Loop"); 73 | } 74 | 75 | 76 | void loop() { 77 | 78 | if (buttondown == 0) { // if button pressed stop circle 79 | dx = (FACTOR * sin(t)); 80 | dy = (FACTOR * cos(t)); 81 | delay(10); 82 | 83 | t = t + 0.1; 84 | Serial.print(">> x="); 85 | Serial.print(dx); 86 | Serial.print(" y="); 87 | Serial.print(dy); 88 | Serial.print(" t="); 89 | Serial.println(t); 90 | 91 | // Draw circle with laser pointer 92 | for (int x = 0; x < RESOLUTION; x++) { 93 | stepper1.Move(dx / RESOLUTION, STEPWAIT); 94 | stepper2.Move(dy / RESOLUTION, STEPWAIT); 95 | } 96 | } 97 | else { 98 | buttondown--; // Countdown to start circle drawing 99 | delay(1); 100 | } 101 | 102 | // Allow user to adjust pointer location 103 | if (digitalRead(UP1) == LOW) { 104 | buttondown = 100; 105 | stepper1.Move(0.1); 106 | Serial.println("UP1"); 107 | } 108 | if (digitalRead(DOWN1) == LOW) { 109 | buttondown = 100; 110 | stepper1.Move(-0.1); 111 | Serial.println("DOWN1"); 112 | } 113 | if (digitalRead(UP2) == LOW) { 114 | buttondown = 100; 115 | stepper2.Move(0.1); 116 | Serial.println("UP2"); 117 | } 118 | if (digitalRead(DOWN2) == LOW) { 119 | buttondown = 100; 120 | stepper2.Move(-0.1); 121 | Serial.println("DOWN2"); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # TinyStepper Examples # 2 | 3 | [![arduino-library-badge](https://www.ardu-badge.com/badge/TinyStepper.svg?)](https://www.ardu-badge.com/TinyStepper) 4 | [![Build Test](https://github.com/jasonacox/TinyStepper/actions/workflows/build.yml/badge.svg)](https://github.com/jasonacox/TinyStepper/actions/workflows/build.yml) 5 | 6 | Arduino sketch examples: 7 | 8 | ## TinyStepper-Test ## 9 | 10 | ![28BYJ-48](Stepper28BYJ-48.png) 11 | 12 | Simple test to drive a 4-phase stepper motor using simple Move() and AccelMove() functions. 13 | 14 | ## ATtiny85 Test ## 15 | 16 | Simple test to drive a single 4-phase stepper motor using the small but mighty 8-pin ATtiny85 microprocessor. 17 | 18 | ## Laser Gimbal ## 19 | 20 | ![LaserGimbal](LaserGimbal.png) 21 | 22 | Laser Gimbal with 2 Stepper Motors based on Thingiverse project: 23 | 24 | Test cycles each stepper then draws a circle with the laser pointer. Switches allow users to move the center of the circle (up/down/left/right). 25 | 26 | * Arduino Microcontroller (e.g. Uno) 27 | * 2 x 28BYJ-48 Stepper Motors 28 | * 2 x ULN2003 Driver Board 29 | * 1 x Laser (e.g. 5V 650nm 5mW Red Dot Diode Laser) 30 | * 4 x Microswitches 31 | * 4 x 61k Ohm Resistors (pull up resistor for switches) 32 | * 5V Power Supply (do not power steppers with Arduino) 33 | 34 | ## Robotic Arm ## 35 | 36 | ![RoboticArm](RoboticArm.png) 37 | 38 | Robotic Arm with 3 Stepper Motors based on Thingiverse project: 39 | 40 | Test cycles each stepper and then responds to user switches (up/down) for stepper motion. 41 | 42 | * Arduino Microcontroller (e.g. Mega2560) 43 | * 3 x 28BYJ-48 Stepper Motors 44 | * 3 x ULN2003 Driver Board 45 | * 6 x Microswitches 46 | * 6 x 61k Ohm Resistors (pull up resistor for switches) 47 | * 5V Power Supply (do not power steppers with Arduino) 48 | -------------------------------------------------------------------------------- /examples/RobotArm/README.md: -------------------------------------------------------------------------------- 1 | # Robotic Arm 2 | 3 | Robotic Arm with 3 Stepper Motors based on Thingiverse project: 4 | 5 | ![RoboticArm](https://github.com/jasonacox/TinyStepper/blob/master/examples/RoboticArm.png) 6 | 7 | [![Video](https://img.youtube.com/vi/fzrtDgM6CLM/0.jpg)](https://www.youtube.com/watch?v=fzrtDgM6CLM "Play Video") 8 | 9 | [Arduino Code](RobotArm.ino) for control board. Test cycles each stepper and then responds to user switches (up/down) for stepper motion. 10 | 11 | * Arduino Microcontroller (e.g. Mega2560) 12 | * 3 x 28BYJ-48 Stepper Motors 13 | * 3 x ULN2003 Driver Board 14 | * 6 x Microswitches 15 | * 6 x 61k Ohm Resistors (pull up resistor for switches) 16 | * 5V Power Supply (do not power steppers with Arduino) 17 | -------------------------------------------------------------------------------- /examples/RobotArm/RobotArm.ino: -------------------------------------------------------------------------------- 1 | /* 2 | TinyStepper - 3 Stepper Motor Robotic Arm Test 3 | by Jason A. Cox - @jasonacox 4 | Date: 19 July 2020 5 | 6 | Robotic Arm with 3 Stepper Motors based on Thingiverse project: https://www.thingiverse.com/thing:2838859 7 | Test cycles each stepper and then responds to user switches (up/down) for stepper motion. 8 | 9 | Arduino Microcontroller (e.g. Mega2560) 10 | 3 x 28BYJ-48 Stepper Motors 11 | 3 x ULN2003 Driver Board 12 | 6 x Microswitches 13 | 6 x 61k Ohm Resistors (pull up resistor for switches) 14 | 5V Power Supply (do not power steppers with Arduino) 15 | 16 | Video Demo: https://www.youtube.com/watch?v=fzrtDgM6CLM&feature=youtu.b 17 | */ 18 | 19 | #include 20 | 21 | #define HALFSTEPS 4096 // Number of half-steps for a full rotation 22 | 23 | #define MOTIONTEST false // Cycle arm on startup (set to false for button control only) 24 | #define DELTA 0.125 // Stepper degrees to change per button press loop 25 | #define STEPWAIT 1 // Time to wait for motor to move between steps (-Speed vs Torque+) 26 | 27 | // Motion control microswitches 28 | #define UP1 26 29 | #define DOWN1 27 30 | #define UP2 28 31 | #define DOWN2 29 32 | #define UP3 30 33 | #define DOWN3 31 34 | 35 | // Arduino Pin Outputs to to the ULN2003 for the 28BYJ-48 Stepper Motors 36 | // IN1 IN2 IN3 IN4 37 | TinyStepper stepper1(HALFSTEPS, 8, 9, 10, 11); 38 | TinyStepper stepper2(HALFSTEPS, 4, 5, 6, 7); 39 | TinyStepper stepper3(HALFSTEPS, 22, 23, 24, 25); 40 | 41 | void setup() 42 | { 43 | Serial.begin(38400); 44 | 45 | stepper1.Enable(); 46 | stepper2.Enable(); 47 | stepper3.Enable(); 48 | delay(1000); 49 | 50 | pinMode(UP1, INPUT); 51 | pinMode(DOWN1, INPUT); 52 | pinMode(UP2, INPUT); 53 | pinMode(DOWN2, INPUT); 54 | pinMode(UP3, INPUT); 55 | pinMode(DOWN3, INPUT); 56 | 57 | if (MOTIONTEST) { 58 | Serial.println("Stepper 1 Motion Test"); 59 | stepper1.AccelMove(180); 60 | stepper1.AccelMove(-180); 61 | 62 | Serial.println("Stepper 2 Motion Test"); 63 | stepper2.AccelMove(180); 64 | stepper2.AccelMove(-180); 65 | 66 | Serial.println("Stepper 3 Motion Test"); 67 | stepper3.AccelMove(180); 68 | stepper3.AccelMove(-180); 69 | } 70 | } 71 | 72 | 73 | void loop() { 74 | 75 | if (digitalRead(UP1) == LOW) { 76 | stepper1.Move(DELTA, STEPWAIT); 77 | Serial.println("UP1"); 78 | } 79 | if (digitalRead(DOWN1) == LOW) { 80 | stepper1.Move(-DELTA, STEPWAIT); 81 | Serial.println("DOWN1"); 82 | } 83 | 84 | if (digitalRead(UP2) == LOW) { 85 | stepper2.Move(DELTA, STEPWAIT); 86 | Serial.println("UP2"); 87 | } 88 | if (digitalRead(DOWN2) == LOW) { 89 | stepper2.Move(-DELTA, STEPWAIT); 90 | Serial.println("DOWN2"); 91 | } 92 | 93 | if (digitalRead(UP3) == LOW) { 94 | stepper3.Move(DELTA, STEPWAIT); 95 | Serial.println("UP3"); 96 | } 97 | if (digitalRead(DOWN3) == LOW) { 98 | stepper3.Move(-DELTA, STEPWAIT); 99 | Serial.println("DOWN3"); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /examples/RoboticArm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonacox/TinyStepper/349c6b5c5f4271e31a9d93dbd129f3ec82e9567c/examples/RoboticArm.png -------------------------------------------------------------------------------- /examples/Stepper28BYJ-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonacox/TinyStepper/349c6b5c5f4271e31a9d93dbd129f3ec82e9567c/examples/Stepper28BYJ-48.png -------------------------------------------------------------------------------- /examples/TinyStepper-Test/TinyStepper-Test.ino: -------------------------------------------------------------------------------- 1 | /* 2 | TinyStepper - Stepper Motor Test 3 | 4 | by Jason A. Cox - @jasonacox 5 | 6 | Date: 19 July 2020 7 | 8 | */ 9 | 10 | #include 11 | 12 | // Define Arduino Pin Outputs to to the ULN2003 Darlington Array to drive a 28BYJ-48 Stepper Motor 13 | #define IN1 8 14 | #define IN2 9 15 | #define IN3 10 16 | #define IN4 11 17 | #define HALFSTEPS 4096 // Number of half-steps for a full rotation 18 | 19 | // Initialize the TinyStepper Class 20 | TinyStepper stepper(HALFSTEPS, IN1, IN2, IN3, IN4); 21 | 22 | void setup() 23 | { 24 | Serial.begin(38400); 25 | stepper.Enable(); 26 | delay(1000); 27 | } 28 | 29 | void loop() { 30 | 31 | // Random back and forth 32 | Serial.println("Random Test"); 33 | stepper.Move(45); 34 | stepper.Move(-90); 35 | stepper.Move(120); 36 | stepper.Move(-15); 37 | stepper.Move(30); 38 | stepper.Move(-300); 39 | stepper.Move(600); 40 | stepper.Move(-100); 41 | delay(2000); 42 | 43 | // Accelerate/decelerate 360 full rotation - both directions 44 | Serial.println("Full Rotation"); 45 | stepper.AccelMove(360); 46 | stepper.AccelMove(-360, 1, 10); 47 | delay(2000); 48 | } 49 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Datatypes (KEYWORD1) 3 | ####################################### 4 | 5 | TinyStepper KEYWORD1 6 | 7 | ####################################### 8 | # Methods and Functions (KEYWORD2) 9 | ####################################### 10 | 11 | Begin KEYWORD2 12 | Move KEYWORD2 13 | AccelMove KEYWORD2 14 | Disable KEYWORD2 15 | Enable KEYWORD2 16 | SetPhase KEYWORD2 17 | 18 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TinyStepper", 3 | "keywords": "Stepper, Motor, Tiny, 28BYJ-48, halfstep, UNL2003", 4 | "description": "Arduino library to drive stepper motors. Small and easy to use.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/jasonacox/TinyStepper.git" 8 | }, 9 | "authors": { 10 | "name": "Jason Cox", 11 | "url": "https://jasonacox.com" 12 | }, 13 | "frameworks": "arduino", 14 | "platforms": "*" 15 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=TinyStepper 2 | version=1.2.0 3 | author=Jason Cox 4 | maintainer=Jason Cox 5 | sentence=Arduino library to drive stepper motors. Small and easy to use. 6 | paragraph=Simple library to drive a 4-phase stepper motor using simple Move(), AccelMove() and Disable() functions. Works well with 28BYJ-48 stepper motor and UNL2003 module. Control steppers with basic Move(x) commands where x is positive or negative value (in degrees). Uses halfstep sequencing for higher torque and smoother motion. 7 | category=Device Control 8 | url=https://github.com/jasonacox/TinyStepper 9 | architectures=* 10 | includes=TinyStepper.h 11 | 12 | -------------------------------------------------------------------------------- /src/TinyStepper.cpp: -------------------------------------------------------------------------------- 1 | // TinyStepper 2 | // Arduino tiny library for stepper motors 3 | // 4 | // Author: Jason A. Cox - @jasonacox - https://github.com/jasonacox 5 | // Date: 19 July 2020 6 | 7 | // Includes 8 | #include "Arduino.h" 9 | #include "math.h" 10 | #include "TinyStepper.h" 11 | 12 | // The Stepper Motor is driven by a ULN2003A which provides an array of seven NPN Darlington transistors 13 | // capable of 500 mA, 50 V output, great for driving inductive loads like a motor. 14 | // 15 | // The stepper motor has 4 different position coils, ABCD. In half step mode, you energize the adjacent coil before 16 | // disengaging the previous coil. The transition steps would be these 8 patterns: A, AB, B, BC, C, CD, D, DA 17 | // 18 | // Phase ABCD Coils 19 | // 0 1000 A 20 | // 1 1100 AB 21 | // 2 0100 B 22 | // 3 0110 BC 23 | // 4 0010 C 24 | // 5 0011 CD 25 | // 6 0001 D 26 | // 7 1001 A D 27 | // 28 | // The phase_map[] array is based on the transition steps. ABCD map to IN1, IN2, IN3, and IN4. 29 | 30 | const uint8_t phase_map[] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09}; 31 | 32 | 33 | TinyStepper::TinyStepper(uint16_t halfsteps, uint8_t IN1, uint8_t IN2, uint8_t IN3, uint8_t IN4) 34 | { 35 | 36 | // Copy the pin numbers 37 | m_pinIN1 = IN1; 38 | m_pinIN2 = IN2; 39 | m_pinIN3 = IN3; 40 | m_pinIN4 = IN4; 41 | 42 | steps = halfsteps; 43 | step_angle = (float)(360.0/steps); 44 | phase = 0; 45 | } 46 | 47 | // Initialize the stepper hardware, setting data pins. 48 | void TinyStepper::Begin() 49 | { 50 | Enable(); 51 | } 52 | 53 | // Move stepper 'angle' degrees 54 | void TinyStepper::Move(float angle, uint8_t timedelay ) { 55 | int halfsteps = abs((int)(angle / step_angle)); 56 | int inc = 1; 57 | if (angle < 0.0) { 58 | inc = -1; 59 | } 60 | for (int j = 0; j < halfsteps; j++) { 61 | phase = phase + (inc); 62 | if (phase < 0) phase = 7; 63 | if (phase > 7) phase = 0; 64 | SetPhase(phase); 65 | delay(timedelay); 66 | } 67 | } 68 | 69 | // Move stepper 'angle' degrees and acceleration and deceleration 70 | void TinyStepper::AccelMove(float angle, uint8_t timedelaymin, uint8_t timedelaymax ) { 71 | int halfsteps = abs((int)(angle / step_angle)); 72 | int d; 73 | int inc = 1; 74 | if (angle < 0) { 75 | inc = -1; 76 | } 77 | for (int j = 0; j < halfsteps; j++) { 78 | phase = phase + (inc); 79 | if (phase < 0) phase = 7; 80 | if (phase > 7) phase = 0; 81 | SetPhase(phase); 82 | d = (DelayCurve(timedelaymin, timedelaymax, ((float)j/(float)halfsteps))); 83 | delay(d); 84 | } 85 | } 86 | 87 | // Calculate an acceleration curve - basic sin(x) ramp up and down for first and last 25% of cycle 88 | int TinyStepper::DelayCurve(uint8_t minvalue, uint8_t maxvalue, float percentage) { 89 | float rad; 90 | char delta = maxvalue - minvalue; 91 | if(percentage >= 0.25 && percentage <= 0.75) return(minvalue); 92 | if(percentage < 0.25) rad = (PI/2.0) * (4.0 * percentage); 93 | if(percentage > 0.75 && percentage <= 1.0) rad = (PI/2.0) + ((percentage-0.75)*4.0)*(PI/2.0); 94 | 95 | return(minvalue + delta - (delta * sin(rad))); 96 | } 97 | 98 | // Removes power from motor - free spin 99 | void TinyStepper::Disable() { 100 | digitalWrite(m_pinIN1, 0); 101 | digitalWrite(m_pinIN2, 0); 102 | digitalWrite(m_pinIN3, 0); 103 | digitalWrite(m_pinIN4, 0); 104 | } 105 | 106 | // Set motor to current phase - locked 107 | void TinyStepper::Enable() { 108 | // Set the pins as output 109 | pinMode(m_pinIN1, OUTPUT);//set the IN1 pin as OUTPUT 110 | pinMode(m_pinIN2, OUTPUT);//set the IN2 pin as OUTPUT 111 | pinMode(m_pinIN3, OUTPUT);//set the IN3 pin as OUTPUT 112 | pinMode(m_pinIN4, OUTPUT);//set the IN4 pin as OUTPUT 113 | // Lock Stepper 114 | SetPhase(phase); 115 | } 116 | 117 | // Activate stepper motor to transition to state defined by phase map 118 | void TinyStepper::SetPhase(int8_t p) { 119 | phase = p; 120 | if (phase < 0) phase = 7; 121 | if (phase > 7) phase = 0; 122 | digitalWrite(m_pinIN1, ((phase_map[phase] & 0x01) == 0x01 ? true : false)); 123 | digitalWrite(m_pinIN2, ((phase_map[phase] & 0x02) == 0x02 ? true : false)); 124 | digitalWrite(m_pinIN3, ((phase_map[phase] & 0x04) == 0x04 ? true : false)); 125 | digitalWrite(m_pinIN4, ((phase_map[phase] & 0x08) == 0x08 ? true : false)); 126 | } 127 | 128 | -------------------------------------------------------------------------------- /src/TinyStepper.h: -------------------------------------------------------------------------------- 1 | // TinyStepper 2 | // Arduino tiny library for stepper motors 3 | // 4 | // Author: Jason A. Cox - @jasonacox - https://github.com/jasonacox 5 | // Date: 19 July 2020 6 | // 7 | 8 | #ifndef __TINYSTEPPER__ 9 | #define __TINYSTEPPER__ 10 | 11 | class TinyStepper { 12 | 13 | public: 14 | //! Initialize a TinyStepper object, setting the number of half steps for a revolution and 15 | //! data pins. 16 | //! 17 | //! @param halfsteps - The number of halfsteps for a full revolution (360 degrees) 18 | //! @param IN1 - The number of the digital pin connected to the IN1 of the ULN2003 19 | //! @param IN2 - The number of the digital pin connected to the IN2 of the ULN2003 20 | //! @param IN3 - The number of the digital pin connected to the IN3 of the ULN2003 21 | //! @param IN4 - The number of the digital pin connected to the IN4 of the ULN2003 22 | TinyStepper(uint16_t halfsteps, uint8_t IN1, uint8_t IN2, uint8_t IN3, uint8_t IN4); 23 | 24 | //! Initialize the stepper hardware, setting data pins. 25 | //! 26 | //! This method should be called once (typically in setup()) before calling any other. 27 | //! @note This is an alias to Enable() 28 | void Begin(); 29 | 30 | //! Move the stepper motor forward or backward specified in degrees (float). 31 | //! 32 | //! @param angle - Positive or negative number of degrees to move 33 | //! @param timedelay - Time in milliseconds to wait for each step (default=1) 34 | void Move(float angle, uint8_t timedelay = 1 ); 35 | 36 | //! Move the stepper motor forward or backward specified in degrees but do so by accelerating 37 | //! decelerate the motion to create a smoother transition. 38 | //! 39 | //! Acceleration happens during first 25% of movement, full speed next 50% and decelerate 40 | //! happens the last 25%. 41 | //! 42 | //! @param angle - Positive or negative number of degrees to move 43 | //! @param timedelaymin - Time in milliseconds to wait for each step (default=1) at max speed 44 | //! @param timedelaymax - Time in milliseconds to wait for each step (default=10) at min speed 45 | void AccelMove(float angle, uint8_t timedelaymin = 1, uint8_t timedelaymax = 10); 46 | 47 | //! Disable stepper motor - remove power and allow free spin 48 | //! 49 | //! Removing power will allow the stepper motor to move on its own. It will not be locked. 50 | void Disable(); 51 | 52 | //! Initialize, set pins and engage stepper motor - Will lock stepper motor to current phase 53 | //! 54 | //! This method should be called at least once (typically in setup()) before calling any other. 55 | //! Stepper motor will be locked until sent a Move command. 56 | void Enable(); 57 | 58 | //! Activate stepper motor and transition to state defined by phase map 59 | //! 60 | //! The stepper motor has 4 different position coils, ABCD. In half step mode, you energize the adjacent coil before 61 | //! disengaging the previous coil. The transition steps would be these 8 patterns: A, AB, B, BC, C, CD, D, DA 62 | //! 63 | //! Phase ABCD Coils 64 | //! 0 1000 A 65 | //! 1 1100 AB 66 | //! 2 0100 B 67 | //! 3 0110 BC 68 | //! 4 0010 C 69 | //! 5 0011 CD 70 | //! 6 0001 D 71 | //! 7 1001 A D 72 | //! 73 | //! @param phase The phase to transition to for the stepper motor (default=0) 74 | void SetPhase(int8_t p = 0); 75 | 76 | protected: 77 | 78 | // Calculate an acceleration curve - basic sin(x) ramp up and down for first and last 25% of cycle 79 | int DelayCurve(uint8_t minvalue, uint8_t maxvalue, float percentage); 80 | 81 | private: 82 | uint8_t m_pinIN1; 83 | uint8_t m_pinIN2; 84 | uint8_t m_pinIN3; 85 | uint8_t m_pinIN4; 86 | int8_t phase; 87 | uint16_t steps; 88 | float step_angle; 89 | }; 90 | 91 | #endif // __TINYSTEPPER__ 92 | --------------------------------------------------------------------------------