GithubHelp home page GithubHelp logo

tyhenry / cheapstepper Goto Github PK

View Code? Open in Web Editor NEW
122.0 16.0 46.0 213 KB

Arduino library for the cheap but decent 28BYJ-48 5v stepper motor with ULN2003 board

License: GNU General Public License v3.0

C++ 100.00%

cheapstepper's Introduction

CheapStepper v0.2

An Arduino library for the 28BYJ-48 stepper motor using ULN2003 driver board

created by Tyler Henry, 6/2016

You can read some more info on the cheap yet worthy 28BYJ-48 stepper motor here.

Wiring example

Library Info

Half-stepping

CheapStepper uses an 8 mini-step sequence to perform all moves
(a.k.a half-stepping): A-AB-B-BC-C-CD-D-DA

Gear Ratio

Depending on whom you ask, the 28BYJ-48 motor has an internal gear ratio of either:

  • 64:1 (per manufacturer specs) or
  • 63.68395:1 (measured... see this Arduino Forum topic for more info)

Total Steps

64:1 gear ratio * 64 steps (1 step = 8 mini-steps) per internal motor revolution =
4096 total mini-steps / revolution
or ~4076 (4075.7728) if the gear ratio is 63.68395:1

CheapStepper library defaults to 4096 mini-steps but you can call:
CheapStepper::set4076StepMode() to use 4076 steps or CheapStepper::setTotalSteps(int numSteps) to use a custom amount

Power

CheapStepper assumes a 5v power source for RPM calculations.
It's best to use an external power supply like this, wired directly to the ULN2003 driver board, rather than draw from the Arduino's onboard power, which may have insufficient amperage (>100mA needed).


Blocking Moves

The Arduino sketch "pauses" during move()

  • move (boolean clockwise, int numSteps);
  • moveTo (boolean clockwise, int toStep);
  • moveDegrees (boolean clockwise, int degrees);
  • moveToDegree (boolean clockwise, int toDegree);

Non-blocking Moves

The Arduino sketch will continue running during the move.
You must call run() on your stepper during loop()

  • newMove (boolean clockwise, int numSteps);
  • newMoveTo (boolean clockwise, int toStep);
  • newMoveDegrees (boolean clockwise, int degrees);
  • newMoveToDegree (boolean clockwise, int toDegree);

Note

  • must call run() during loop to continue move
  • call stop() to cancel/end move

Move a Single Mini-Step
(1/8 of 8 Step Sequence)

  • step (boolean clockwise);
  • or stepCW(); or stepCCW();

All move functions have ...CW() or ...CCW() variants:

e.g.

  • move 8 steps clockwise:
    move (true, 8); is the same as
    moveCW (8);
  • create new move of 90 degrees counter-clockwise
    newMoveDegrees (false, 90); is the same as
    newMoveDegreesCCW (90);

cheapstepper's People

Contributors

tyhenry avatar werfra avatar zimnyjakub avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cheapstepper's Issues

README references dead link

You can read some more info on the cheap yet worthy 28BYJ-48 stepper motor here.
--------------------------------------------------------------------------------------------------^
Dead link.

CheapStepper::move/newMove - numSteps should the long instead of int

At the moment CheapStepper::move has a parameter with the number of steps you want to step the motor. The numSteps parameter is defined as an int which only give you room to turn it maximum about 8 full revolutions. If this was defined as a Long instead we would have a lot of more possibilities.

These are the changes needed to be done:
CheapStepper.cpp
Row 49: void CheapStepper::move (bool clockwise, long numSteps)
Row 91: void CheapStepper::newMove (bool clockwise, long numSteps){

CheapStepper.h
Row 45: void move (bool clockwise, long numSteps);
Row 63: void newMove (bool clockwise, long numSteps);
Row 95: long getStepsLeft()
Row 124: long stepsLeft = 0

This may affect the other functions as well, but I haven't tested those.

newMoveTo does not work correctly with toStep less than current position

If toStep is less than stepN the move to is incorrect. This also affects newMoveToDegree.

My solution:

void CheapStepper::newMoveTo (bool clockwise, int toStep){

	// keep toStep in 0-(totalSteps-1) range
	if (toStep >= totalSteps) toStep %= totalSteps;
	else if (toStep < 0) {
		toStep %= totalSteps; // returns negative if toStep not multiple of totalSteps
		if (toStep < 0) toStep += totalSteps; // shift into 0-(totalSteps-1) range

	lastStepTime = micros();

	}

	if (clockwise) { // drp correction for moveto < current position
		if (toStep < stepN) toStep = toStep + totalSteps;
	stepsLeft = toStep - stepN;
	//stepsLeft = abs(toStep - stepN);
	}
	else {
		if (toStep < stepN) { // drp correction for moveto < current position

		stepsLeft= toStep - stepN;
		}else{
		//stepsLeft = -1*(totalSteps - abs(toStep - stepN));
		stepsLeft = -1*(totalSteps - (toStep - stepN));
		}
	}
	
lastStepTime = micros();
}

As a bonus, abs no longer needed

David

Problem using other pins besides defaults

I dont think pin assignments are working beyond the default.
I was able to fix by pinMode( x, OUTPUT);

Made script that used 3 28byj steppers, it wasn't working, tried setting pinMode to OUTPUT on all used pins and everything started working.

Object Initializers issue

Does the current implementation of the inizializer
CheapStepper (int in1, int in2, int in3, int in4);
work? I've found that the pins mode was not changed when declaring the stepper before the setup using it.
I'm in a hurry so I just added a begin() method that does the same as in CheapStepper() in the setup and that fixed the problem.
I hope I'm making sense and not mistaking the purpose of the library.

Error in cheapstepper library

What does these lines mean?

C:\Users\OOIYAN~1\AppData\Local\Temp\ccFYj6Na.ltrans0.ltrans.o: In function `__base_ctor ':

C:\Users\ooi yan liang\Documents\Arduino\libraries\CheapStepper/CheapStepper.cpp:31: undefined reference to `pinMode'

c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/../../../../avr/lib/avr5/crtatmega328p.o:(.init9+0x0): undefined reference to `main'

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board Arduino/Genuino Uno.

newMoveDegrees in minus

Hi, can CheapStepper do this? stepper.newMoveDegrees (moveClockwise, -180); So it will move counter clockwise?

After any move the stepper remains in a high current state

My stepper draws 200mA when moving and 370mA when the move has completed.
It would be useful to have an idle call which sets the stepper control lines to zero:

This works:
void idle(); // drp CheapStepper.h

void CheapStepper::idle(){
      seq(8);      // drp CheapStepper.cpp
}

This utilises the default case in switch(seqNum) of void CheapStepper::seq (int seqNum)

If the function is called on the completion of a move, the current drops to 30mA !
The next move appears un-affected.

stepper.run();
  if (stepper.getStepsLeft() == 0){
  // if the current move is done...
  stepper.idle(); // low current

David

Crashing on NodeMCU

I am not entirely sure where the error lies here, but I am trying to use a NodeMCU v1 together with a ESP-12E Motor Shield and a 28BYJ stepper motor. According to this link, the pins shall be 5, 0, 4, 2 or D1, D3, D2, D4.

However, when I try to spin the motor, I get a crash loop while I can hear the motor, but the shaft is not spinning. This is how the crash looks:

17:48:39.891 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
17:48:39.891 -> 
17:48:39.891 -> Soft WDT reset
17:48:39.891 -> 
17:48:39.891 -> >>>stack>>>
17:48:39.891 -> 
17:48:39.891 -> ctx: cont
17:48:39.891 -> sp: 3ffffd60 end: 3fffffc0 offset: 01a0
17:48:39.891 -> 3fffff00:  4020297d feefeffe feefeffe feefeffe  
17:48:39.891 -> 3fffff10:  40100250 00000010 3ffee2e8 40100279  
17:48:39.926 -> 3fffff20:  3ffe8622 3ffee2e8 00000010 4020120c  
17:48:39.926 -> 3fffff30:  00000001 00000001 00000000 00000000  
17:48:39.926 -> 3fffff40:  40201344 3ffee2e8 3ffee2e8 4020123a  
17:48:39.926 -> 3fffff50:  40201344 3ffee330 00000739 4020129d  
17:48:39.926 -> 3fffff60:  3ffee310 0000000c 3ffee330 402012cc  
17:48:39.960 -> 3fffff70:  3ffee310 3ffee330 3ffee330 00000800  
17:48:39.960 -> 3fffff80:  3ffee310 3ffee330 3ffee2e8 40201080  
17:48:39.960 -> 3fffff90:  feefeffe feefeffe feefeffe 3ffee398  
17:48:39.960 -> 3fffffa0:  3fffdad0 00000000 3ffee358 40201b80  
17:48:39.960 -> 3fffffb0:  feefeffe feefeffe 3ffe84e0 40100be9  
17:48:39.997 -> <<<stack<<<

This is the code:

#include <CheapStepper.h>

bool stepped = false;
const int stepsPerRevolution = 2048;

CheapStepper motor(D1, D3, D2, D4);

void setup() {
  Serial.begin(74880);
  motor.setTotalSteps(stepsPerRevolution);
  motor.setRpm(17);
  
  Serial.println("UP");

  if (!stepped)
  {
    Serial.println("stepping ...");
    motor.move(true, stepsPerRevolution);
    stepped = true;
  }  
}

Can someone help me out? Is the NodeMCU or the shield maybe not compatible with this library?

I do know that the motor works with that board, because I was using the LUA firmware before, but now want to use C++/Arduino IDE.

Two steppers issue

Hi,

I have used 2 steppers and works only one (LEFT),

`
// RIGHT
#define R_IN1 4
#define R_IN2 5
#define R_IN3 6
#define R_IN4 7

// LEFT
#define L_IN1 8
#define L_IN2 9
#define L_IN3 10
#define L_IN4 11

CheapStepper L_motor (L_IN1,L_IN2,L_IN3,L_IN4);
CheapStepper R_motor (R_IN1,R_IN2,R_IN3,R_IN4);
`

but with other lib like (AccelStepper + MultiStepper) works good.

Is your lib designed to using 2 steppers?

Best Regards,
AndyGFX

Reset position to 0

Hi
Great work on CheapStepper. I am using it in a project and it is working well I would be grateful if you could help with the following please;
When I power up the project I have the stepper set a dial to to the zero position using a sensor. Before I power on the dial could be in any position. Unfortunately for other reasons cannot set this position to zero at power down.
What I would like to do is once I have reached this zero position is to set the position in CheapStepper as zero so if I say move to position 2048 it rotates the dial halfway (180 degrees)
My problem is that CheapStepper effectively sets position zero at power on and I would like to set this at any point in my sketch. What would be great is a command like stepper.(resetposition(0)) Which would set it to zero or any other value entered without moving the stepper. If I then used the command Serial.print(stepper1.getStep()) it would tell me the position is to the value I'd set.
They may already be a way to do this but I am struggling to find it.
Any help would be most appreciated.
Thank you
Charin

Setting 4 non default pins does not work and a 2 motor example would be useful

On ide 1.6.12 the non default call CheapStepper stepper(4, 5, 6, 7);
results in the default pins (8, 9, 10, 11) being set.

if line 41 of the library .cpp file is altered from
CheapStepper();
to
for (int pin = 0; pin < 4; pin++) pinMode(pins[pin], OUTPUT);
the new pins work.

The Non-blocking functions are very useful!
My example allows simultaneous control of two stepper motors with simple left, right, forward and backward functions:

/*
 * Stepper_cheap_newMoveTo3.ino
 * Controls 2 motors at once with simple
 * forward, backward,
 * left and right functions
 * D.R.Patterson
 * 15/03/2016
 * 
 * ///////////////////////////////////////////
 * using CheapStepper Arduino library v.0.2.0
 * created by Tyler Henry, 7/2016
 * ///////////////////////////////////////////
 * 
 * This sketch illustrates the library's
 * "non-blocking" move functions -
 * i.e. you can perform moves with the stepper over time
 * while still running other code in your loop()
 * 
 * This can be useful if your Arduino is multi-tasking,
 * but be careful: if the other code in your loop()
 * slows down your Arduino, the stepper motor may
 * slow down or move with a stutter
 * 
 * //////////////////////////////////////////////////////
 */

// first, include the library :)
#include <CheapStepper.h>


// next, declare the stepper
// and connect pins 8,9,10,11 to IN1,IN2,IN3,IN4 on ULN2003 board

CheapStepper stepper1(8, 9, 10, 11);
CheapStepper stepper2(4, 5, 6, 7);  

const unsigned int steps = 4096;
const unsigned int halfRev = steps / 2;
boolean onedone = false;
boolean twodone = false;

void setup() {

// let's run the stepper at 12rpm (if using 5V power) - the default is ~16 rpm
stepper1.setRpm(12);
stepper1.setTotalSteps(steps);
stepper2.setRpm(12);
stepper2.setTotalSteps(steps);
  
/* 
the default steps is 4096 and could be omitted
is geared 63.68395:1 (measured) rather than 64:1 (advertised)
which would make the total steps 4076
for more info see: http://forum.arduino.cc/index.php?topic=71964.15
*/
  
// let's print out the RPM to make sure the setting worked
Serial.begin(115200);
  while(!Serial) yield();
Serial.print("Stepper1 RPM: "); Serial.print(stepper1.getRpm());
Serial.print(", Stepper2 RPM: "); Serial.println(stepper2.getRpm());
Serial.print("Stepper1 delay (micros): "); Serial.print(stepper1.getDelay());
Serial.print(", Stepper2 delay (micros): "); Serial.println(stepper2.getDelay());
Serial.println();
forward(360);
}

void loop() {
static unsigned int counter = 0;

// we need to call run() during loop() 
// in order to keep the stepper moving
stepper1.run();
stepper2.run();

  // if the current moves are done...
  if (!onedone)if (stepper1.getStepsLeft() == 0) onedone = true;
  if (!twodone)if (stepper2.getStepsLeft() == 0) twodone = true;
  
  if (twodone && onedone){
  counter ++;
    if(counter == 8){ // lets start again
    Serial.println("____________________________________\n");
    counter = 0;
    delay(3000);
    }
    switch (counter) {
    case 0:
      forward(360);
      break;
    case 1:
      forward(360);
      break;
    case 2:
      left(90);
      break;
    case 3:
      forward(1080);
      break;
    case 4:
      backward(360);
      break;
    case 5:
      right(270);
      break;
    case 6: 
      forward(720);
      break;
    case 7:
      left(90);
      break;
    }
  }
}
  
void forward(unsigned int mydegrees){
Serial.print("Forward "); Serial.println(mydegrees); Serial.flush();  
onedone = false;
twodone = false;
stepper1.newMoveDegrees (0, mydegrees); // n degrees from current position
stepper2.newMoveDegrees (1, mydegrees);
}

void backward(unsigned int mydegrees){
Serial.print("Backward "); Serial.println(mydegrees); Serial.flush();  
onedone = false;
twodone = false;
stepper1.newMoveDegrees (1, mydegrees); // n degrees from current position
stepper2.newMoveDegrees (0, mydegrees);
}

void left(unsigned int mydegrees){
Serial.print("Left "); Serial.println(mydegrees); Serial.flush();  
onedone = false;
twodone = false;
stepper1.newMoveDegrees (1, mydegrees); // n degrees from current position
stepper2.newMoveDegrees (1, mydegrees);
}

void right(unsigned int mydegrees){
Serial.print("Right "); Serial.println(mydegrees); Serial.flush();  
onedone = false;
twodone = false;
stepper1.newMoveDegrees (0, mydegrees); // n degrees from current position
stepper2.newMoveDegrees (0, mydegrees);
}

David

newMoveToDegree Int overflow in toStep variable

int toStep = deg * totalSteps / 360 does not create correct value
Solved using:

void CheapStepper::newMoveToDegree (bool clockwise, int deg){

	// keep to 0-359 range
	if (deg >= 360) deg %= 360;
	else if (deg < 0) {
		deg %= 360; // returns negative if deg not multiple of 360
		if (deg < 0) deg += 360; // shift into 0-359 range
	}
	float f = totalSteps / 360.0; // drp
	int toStep = 0.5 + deg * f;
	newMoveTo (clockwise, toStep);
}

David

Reset Loop while using WebServer on 8266

I am trying to run a very basic web server (relevant code included below) and am stuck in a reset loop. The starting setup line is never reached. I am using platformio to include the library and compile the code. Ultimately, I'd like to be able to trigger two stepper motors and an LED from a website hosted on the ESP. I have tried a number of variations on how to construct the stepper object with the same result each time. Any ideas? Thanks!

#include <CheapStepper.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

CheapStepper stepper1 (D1,D2,D3,D4);
ESP8266WebServer server(80);

void setup() {
	Serial.begin(115200);
	Serial.println("starting setup");

	WiFi.mode(WIFI_AP);
	uint8_t mac[WL_MAC_ADDR_LENGTH];
	WiFi.softAPmacAddress(mac);
	String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
		String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
	macID.toUpperCase();
	String AP_NameString = "IOT " + macID;

	char AP_NameChar[AP_NameString.length() + 1];
	memset(AP_NameChar, 0, AP_NameString.length() + 1);

	for (int i = 0; i<AP_NameString.length(); i++)
		AP_NameChar[i] = AP_NameString.charAt(i);

	WiFi.softAP(AP_NameChar);
	Serial.printf("Connect to Wi-Fi access point: %s\n", AP_NameChar);
	Serial.println("and open http://192.168.4.1 in your browser");

	stepper1.setRpm(12);
	stepper1.set4076StepMode();

	server.on("/motor", HTTP_POST, []() {
		uint8_t degrees = server.arg("degrees").toInt();
		stepper1.newMoveToDegree(true, degrees);
		String json = String("Received");
		server.send(200, "text/json", json);
		json = String();
	});

	server.begin();

	Serial.println("HTTP server started");

}

void loop() {
	server.handleClient();
	stepper1.run();
}

"Centering" the stepper motor

I wanted to set the start position of the stepper and attached an opto sensor to allow the stepper motor to be moved until a hole in a rotated cardboard disc, caused the opto to read Low.
This all went to plan until I realised that the library initialised its position from the first call to CheapStepper stepper (8,9,10,11) .
I realised I needed a new library call (stepReset) to set stepN = 0 and hence establish a new base position.

void CheapStepper::stepReset(){

      stepN = 0; 
}

This works well.

My centering code;


byte a =  digitalRead(12);  // opto sensor on pin 12
  if(a==1){
  Serial.println("Centering..");
    while(a == 1){
    stepper.move (moveClockwise, 1);
    a = digitalRead(12);
    }
  stepper.stepReset(); // reset position count
  Serial.println("Centred"); Serial.flush();
  stepper.newMove(moveClockwise, 0); // fixes a restart issue
  }

Others may find this useful,

David

Increasing number of steps

This code works wonderfully, but I am attempting to utilize it and am needing a significant number of increase in steps to utilize it as I need. Your current code shows 4076 or 4096 steps per rev... but I am looking to do what I need in 11960 steps (long story short, it's for a DSLR star tracking mount and I need the increased speed to properly track stars at my specific camera lens size).

Would I just need to change the instances of 4076/4096 to the number of steps I need for my use of this?

Ex:

void set11960StepMode() { totalSteps = 11960; }
void setTotalSteps (int numSteps) { totalSteps = numSteps; }
// allows custom # of steps (usually 4076)

// blocking! (pauses arduino until move is done)
void move (bool clockwise, int numSteps); // 11960 steps = 1 revolution
void moveTo (bool clockwise, int toStep); // move to specific step position
void moveDegrees (bool clockwise, int deg);
void moveToDegree (bool clockwise, int deg);

I am not a very fluent coder, so pardon my ignorance on this. Any help you might be able to provide would be much appreciated!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.