Go Down

Topic: New Libray for L298N (Read 7793 times) previous topic - next topic

sbright33

Mar 29, 2012, 06:41 pm Last Edit: Mar 30, 2012, 07:58 pm by sbright33 Reason: 1
I modified my 28BYJ library for L298N with 1.8 degrees per step on a big powerful motor (<1 deg per half step)
http://arduino-info.wikispaces.com/MotorDrivers
You can buy the boards for cheap above.

In addition to this simple library attached as zip, I have another more complex Sketch which requires lots of wiring to 8 pins on the Uno.  It uses PWM to vary the average voltage on each pin.  This drives the stepper in Sine step mode.  It is much smoother without vibration and runs cooler at slow speeds.  It also goes significantly faster.  Yet without removing the hardware you can run in digital mode with the sketch below.  This sketch does not require any special circuit beyond the driver board itself.  That's why I decided to start with this one first.  You will recognize the variables and function names because I got them from my old library.  Like before you can supply my 1v motor with 5v and it will run very cold.  I used the regulator on the Uno.  Or 12v using 1/4 duty cycle and it will only get warm, with much more torque.  At the full voltage you cannot stop a 3/4" bolt from turning with your fingers no matter how hard you squeeze.  I've gotten it to go 350RPM with PWM or 300RPM without using this sketch.  There is a torque difference.  

I've included limited simple speed ramping, and the ability to run other tasks at the same time, even at full speed.
The functions look like this:

void degrpm1A(boolean bcw, long deg100, int rpm100)

Please test it.
Questions?
Steve
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

sbright33

Here it is much easier to see:
Code: [Select]

#define dw digitalWrite
#define dm delayMicroseconds
#define de delay
#define P(s) Serial.print(s);
#define P32 Serial.write(32);
#define P13 Serial.write(10);
#define fastout {pinMode(mp1,OUTPUT);pinMode(mp2,OUTPUT);pinMode(mp3,OUTPUT);pinMode(mp4,OUTPUT);}
#define fastin  {pinMode(mp1,INPUT );pinMode(mp2,INPUT );pinMode(mp3,INPUT );pinMode(mp4,INPUT );}
const int mp1 = 2; // Blue   - 28BYJ48 pin 1
const int mp2 = 3; // Pink   - 28BYJ48 pin 2
const int mp3 = 4; // Yellow - 28BYJ48 pin 3
const int mp4 = 5; // Orange - 28BYJ48 pin 4
                        // Red    - 28BYJ48 pin 5 VCC
long motorSpeed=3000;   // set stepper speed, period actually, changed long for 1A not used?
int stepnum=0;          // current microstep 0-7
int movecnt=0;          // running total of steps taken in move(), &=4095 in moveto
long m;                 // millis()

void setup() {
  fastout
  //Serial.begin(9600);
}
void loop(){
//half step wo 1uf cap 1k res st07()
//10x faster, 10x more deg/step than little motor 64:1 gear
//600 fastest
//1000 stronger
//1600 1/4 duty
//2000 1/4 ideal no vibe but weak
//3200 1/4 slowest wo vibe, smoother=full duty
//5000 slowest full duty
//3000 fastest st03aw (3v critical) same speed as 1500 1/4 duty cuz 4/8 steps
//5000 strong w 1uf caps st03aw
//900 full step st03() is 450 faster than half step
//degrpm1Arampduty(0,18000,10000); de(500);
//degrpm1Arampduty(1,18000,10000); de(500);
degrpm1Aslow(1,18000,100); de(500);
}
void st07(){
if(stepnum==-1)stepnum=7;
if(stepnum== 8)stepnum=0;
switch(stepnum){
case 0:
  dw(mp4, HIGH);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, LOW);
  break;
case 1:
  dw(mp4, HIGH);
  dw(mp3, HIGH);
  dw(mp2, LOW);
  dw(mp1, LOW);
  break;
case 2:
  dw(mp4, LOW);
  dw(mp3, HIGH);
  dw(mp2, LOW);
  dw(mp1, LOW);
  break;
case 3:
  dw(mp4, LOW);
  dw(mp3, HIGH);
  dw(mp2, HIGH);
  dw(mp1, LOW);
  break;
case 4:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, HIGH);
  dw(mp1, LOW);
  break;
case 5:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, HIGH);
  dw(mp1, HIGH);
  break;
case 6:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, HIGH);
  break;
case 7:
  dw(mp4, HIGH);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, HIGH);
  break;
}
//for all cases
dm(motorSpeed);
}
void st03(){
if(stepnum==-1)stepnum=3;
if(stepnum== 4)stepnum=0;
switch(stepnum){
case 0:
  dw(mp4, HIGH);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, LOW);
  break;
case 1:
  dw(mp4, LOW);
  dw(mp3, HIGH);
  dw(mp2, LOW);
  dw(mp1, LOW);
  break;
case 2:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, HIGH);
  dw(mp1, LOW);
  break;
case 3:
  dw(mp4, LOW);
  dw(mp3, LOW);
  dw(mp2, LOW);
  dw(mp1, HIGH);
  break;
}
//for all cases
dm(motorSpeed);
}
void off(){
  dw(mp1, LOW);
  dw(mp2, LOW);
  dw(mp3, LOW);
  dw(mp4, LOW);
}
void topspeed_nocap(int cw){
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
//900,1200 works
if(movecnt%100)dm(1500); else dm(1800);
}
void toppwr(int cw){
//define volt 1 no need
motorSpeed=1;
stepnum-=cw;
movecnt++;
st03();
fastout;  //already?
dm(2000);
}
void degrpm1A(boolean bcw, long deg100, int rpm100) {
int cw;
if(bcw) cw=1; else cw=-1;
//rpm100=10000;  //300RPM max 100RPM 5v runs cold
//motorSpeed overflow when RPM=1 use d in 1Aslow() instead
//use mydelayus() in st07() for multitasking untested
motorSpeed=(long(14630)*4096/4  )/rpm100-20;
//motorSpeed/=4;  //1/4 duty warm 10RPM still ok full duty? IC hotter than motor?
for(int i=0;i<deg100*40/36/100;i++) {
stepnum+=cw;
movecnt++;
st07();  //st07 is half step 1500 fastest
//off();dm(motorSpeed*3);  //1/4 duty
}}
void degrpm1Arampduty(boolean bcw, long deg100, int rpm100) {
int cw;
if(bcw) cw=1; else cw=-1;
rpm100=5000;  //300RPM max 100RPM 5v runs cold 100RPM max 1/4 duty >250 skips on start no load
//cannnot spin DSLR at 100RPM?
//use mydelayus() in st07() for multitasking and dm and delay at bottom untested
motorSpeed=2*(long(14630)*4096/4  )/rpm100-20;
for(int i=0;i<10;i++) {
stepnum+=cw;
movecnt++;
st07();
}
motorSpeed=  (long(14630)*4096/4  )/rpm100-20;
for(int i=0;i<10;i++) {
stepnum+=cw;
movecnt++;
st07();
}
motorSpeed/=4;
for(int i=0;i<deg100*40/36/100-20;i++) {
stepnum+=cw;
movecnt++;
st07();
off();dm(motorSpeed*3);  //1/4 duty
}
st07();delay(500);  //hold for 1/2s
off();
}
void degrpm1Aslow(boolean bcw, long deg100, int rpm100) {
int cw,d;
if(bcw) cw=1; else cw=-1;
//motorSpeed overflow when RPM=1 use d instead
//jerky like drum beat when 5v half step st07() cuz cannot drive 2 coils on same side of board/LED's adjacent
//use st03() instead
motorSpeed=(long(14630)*4096/4  )/rpm100-20;  //*1000 below microsec
d=         (long(1463 )*4096/400)/rpm100; motorSpeed=1;
//d/=2;  //1/2 duty continuous only warm at 10RPM
for(int i=0;i<deg100*40/36/100;i++) {
stepnum+=cw;
movecnt++;
st07();  //st07 is half step 1500 fastest
mydelay(d);  //motorSpeed tiny in st07
//off();mydelay(d);  //1/2 duty
}}
void mydelay(long d){
long ms=millis();
while(millis()<ms+d) {
//10RPM is 15ms
//do anything here instead of delay(1)
delay(1);
}}
void mydelayus(long d){
long ms=micros();
while(micros()<ms+d) {
//100RPM is 1500us
//do anything here instead of delay
delayMicroseconds(100);
}}
/*
need 1uf cap and 1k res:
sto3aw
sinemod
stophold
topspeed
lowpmid
slowpwr
!toppwr
!st03
*/
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

robtillaart


A quick look with one remark to improve your work: use function and variable names that are descriptive and you can leave out 98% of the comments..

e.g.

Code: [Select]
const int mp1 = 2; // Blue   - 28BYJ48 pin 1   ==>    const uint8_t bluePIn = 2;  //uint8_t == byte    or  use #define BLUEPIN 2

long m;                 // millis()   ==>   unsigned long millisec;     // millis() returns unsigned long ; duration might be better name?

void st07()    // I don't know what st07 does from its name...
{...

dw(mp4, HIGH);   ==> digitalWrite(ORANGE, HIGH);  is far more readable, shorter functionNames do not execute faster (unfortunatelly :)


motorSpeed is an example of a excellent descriptive name


Furthermore you could write a function like
Code: [Select]

void setLines( int blue, int pink, int yellow, int orange)   // the name is not ok but
{
  digitalWrite(BLUEPIN, blue);
  digitalWrite(PINKPIN, pink);
  digitalWrite(YELLOWPIN, yellow);
  digitalWrite(ORANGEPIN, orange);
}


such a function would change the switch into
Code: [Select]

switch(stepnum){
case 0:
  setlines(HIGH, LOW, LOW, LOW);
  break;
case 1:
  setlines(HIGH, HIGH, LOW, LOW);
  break;
case 2:
  setlines(LOW, HIGH, LOW, LOW);
  break;
case 3:
  setlines(LOW, HIGH, HIGH, LOW);
  break;
case 4:
  setlines(LOW, LOW, HIGH, LOW);
  break;
case 5:
  setlines(LOW, LOW, HIGH, HIGH);
  break;
case 6:
  setlines(LOW, LOW, LOW, HIGH);
  break;
case 7:
  setlines(HIGH, LOW, LOW, HIGH);
  break;
}


The above "screams" for an array which holds these HIGH LOW patterns and then the whole switch could become a oneliner 

setLines(pattern[stepnum]);

you need the array:

Code: [Select]

uint8_t pattern[8] = { B00001000, .... };  // 1 is HIGH, 0 = LOW

setLines(uint8_t val)
{
  if (val & B0001000) digitalWrite(BLUEPIN, HIGH);
  else digitalWrite(BLUEPIN, LOW);
  if (val & B0000100) digitalWrite(PINKPIN, HIGH);
  else digitalWrite(PINKPIN, LOW);
  if (val & B0000010) digitalWrite(YELLOWPIN, HIGH);
  else digitalWrite(YELLOWPIN, LOW);
  if (val & B0000001) digitalWrite(ORANGEPIN, HIGH);
  else digitalWrite(ORANGEPIN, LOW);
}


Hope this helps you to improve your library.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

sbright33

Thanks for your feedback I appreciate your taking the time to look at it.  dw and st07 work for me, but I can see it would be difficult for others to know what it means without reading my mind.  st07 simply means steps going from 0-7.  I could spend time changing it from a case statement to bit arrays, but instead I just copied and pasted that from another Sketch without testing.  I will try to do better by either commenting or using longer variable names in the future.  You can't make me do both!  ;-)  Kidding...  S
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

sbright33

motorSpeed is a horrible example of a descriptive name for a variable.  This is an example of where it is a bad idea to try to describe the variable in its name.  Really I should have called it motorPeriod or motorPeriodOneOverSpeed.  MotorSpeed is literally the opposite of what the variable is meant to do in the code.  Yet it works and it's readable!  If you overlook the fact that it's exactly wrong.  Can you imagine if I used Go for a boolean variable that Stops a motor.  Bad idea.  Sometimes using n or b is better.  Instead of stopWhenItsRainingOutside.  I hate all the Caps because you have to push the shift key.  I guess it's better than stop_when_its_raining_outside.  I prefer to use a comment instead.  Just my opinion.

If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

robtillaart

I also like short variable names as I don't like typing long names. However I learned that descriptive names (not necessary long) was the most important improvement to understand my own programs after 6 months much faster. Most newer IDE's like visual Studio have name completion so you don't have to type that much.

There are typical cases when you need a for loop than i and j are still favorite.

In Arduino you could write in shorthand notation like DW(PIN, LOW) and do a global search/replace . But in the end its just a choice, if it is a test program, who care, if it is to be maintained by me at least I care :)

Tip: why not using L for LOW and H for HIGH?  Everyone would understand those macros.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

sbright33

Often I use 0 or 1.  Just as short as L or H.
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

robtillaart

Very true as long as the defintions of LOW and HIGH are not changed  :)

from wiring.h
#define HIGH 0x1
#define LOW  0x0
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart


Got another sleep over your code and you could write a library for your abbreviated notations, easy to reuse in all your sketches.

just make a folder abbrev under libraries and put this one in. Not tested and to be extended :)

Code: [Select]

//
//    FILE: abbrev.h
//  AUTHOR: Rob Tillaart
//    DATE: 2012-03-30
//
// PUPROSE: short notation of many Arduino specific commands
//
#ifndef ABBREV_H
#define ABBREV_H

#define L LOW
#define H HIGH

#define po(P) pinMode(P, OUTPUT)
#define pi(P) pinMode(P, INPUT)

#define dr(P) digitalRead(P)
#define dw(P,V) digitalWrite(P,V)

#define ar(P) analogRead(P)
#define aw(P,V) analogWrite(P,V)
#define aref(X) analogReference(X)

#define si(D,C,B)         shiftIn(D, C, B)
#define so(D,C,B,A) shiftOut(D, C, B, A)

#endif
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

sbright33

Hey you're making it easier for me to do what you told me not to!  You forgot to say Simon Says?
Maybe it's some kind of programmer sarcasm...

http://en.wikipedia.org/wiki/Stepper_motor
I've been thinking about my code too.  Tried Full step drive with 2 phases always on instead of the obsolete wave drive I'm using.  It didn't improve the performance one bit, in fact it got worse.  This is due to the limitations of my walwart power supply of only 2 amps.  In theory it should improve the torque and maximum speed, but the IC and motor would over heat much faster.  I considered adding this function to my older library but that would be even hotter than the big motor. 

I fixed an error at the top of my thread.  1.8 degrees.

Saw some motors on sale 24v 200ma?  What is the advantage of this higher coil resistance?
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

sbright33

http://www.bgmicro.com/mot1070.aspx

What is the advantage of a high coil resistance compared to a 1v motor?
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

robtillaart

Quote
Hey you're making it easier for me to do what you told me not to!  You forgot to say Simon Says?
Maybe it's some kind of programmer sarcasm...


No not sarcasm, the idea is, if you choose for a certain style, do it to the max ;)  A reusable library is then the way to go.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

dhunt

Those driver circuits all seem to be skipping the current sense resistor, which means you can't do chopping with the driver. Does't that limit the max voltage and torque you can get out of the stepper?

joogaa

I found this online:
Inductance / Resistance = time constant of the coil
The higher the time constant of your coil, the greater magnetic field you produced for a given power supply.

sbright33

You are correct.  But it depends on your perspective.  I am sending the maximum voltage that I have available from my PS to a motor which is designed to run continuously on 1-2v.  The 12v supply can only provide 2A instead of the 4A that it might draw.  Because there is no sense resistor I am letting too MUCH current flow.  It would overheat if it were allowed to continue without pause.  If it is running for only a short movement and period I ignore this limit.  At top speeds there is no other choice, the running time is limited before the motor overheats (without PWM).  At slower speeds you can choose to apply the maximum voltage for 50-100us, then rest between steps.  This keeps it running cool and achieves results similar to chopping, but with a manual adjustment instead of sensing.  In effect I am choosing the timing of when to chop manually.  Instead of using peak current as my criteria, I am maximizing the temperature after running for 5 minutes, to keep it from overheating.  I am forced to work within the current limitations of my small power supply.  I don't think 12v is a restraining limit for my motor.  2A is below the maximum current.  Alternatively I could buy a bigger supply, or use a large capacitor to supply more current for 50us.  A chopper circuit would increase the peak current, if it were available from the supply.  This would not lower the temperature at the torque I have already achieved.  So I am not motivated to make any changes to my circuit.  Summary: In my setup the temperature of the motor and IC are the limiting factors.  Chopping would not reduce them at the same torque.

I would love to hear a different point of view?

@joogaa- I do like low resistance coils for that reason!
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

Go Up