Go Down

### Topic: [SOLVED] First lessons from using a stepper (Read 1 time)previous topic - next topic

#### Botolph

##### Sep 21, 2014, 02:15 amLast Edit: Sep 21, 2014, 06:43 pm by Botolph Reason: 1
(note if you just want some sample code go to my post on 21st September)

After much searching the web and bashing my head against the wall I have my stepper actually going round. Which doesn't make me an expert.

On the way it has sat doing nothing ,  buzzing but doing nothing and generally being annoying. So, in case I forget, and with the possibility that it is of help to someone else, I post my observations. And I will put them in a more useful order than the order in which I found them.

I am using a stepper driver from Arc Euro and a hybrid motor with an Uno.

The first puzzle was the eight wires coming out of the motor together with the four terminals on the driver. The instructions with the hybrid motor required joining pairs of wires that would result in one of three configurations: BiPolar SERIES, BiPolar PARRALLEL, and UniPolarFour Phase.
So which should I use? The driver is described as a BiPolar Stepper - so that left two. In fact, I found out, that for my purposes there isn't much differences between the three the differences are the profile of acceleration and torque. So I merrily went for BiPolar SERIES. Apart from getting the pairs of wires right the driver didn't mind which way round I put them.

Power to the driver was rated at anything between 18V and 50V. That was easy.

Them came the impressive array of DIP switches.
The easy one is : number of pulses per revolution. I had a problem partly caused by this being at the highest value. Start low is my advice.
Current is interesting. The motor is rated at 2A per Phase. With DIP switch options for 1.93 and 2.4 which should I choose? I then found very clear instructions that the current should be the minimum value that will work and must not exceed the motor's requirement. So I have mine at 1.9 and it is working. (originally I had it set to maximum and I got very odd readings off the voltmeter on my power supply and the motor did not work. But there may have been other contributory reasons!)
There is an automatic half-current-mode switch which I left at automatic.

And an internal jumper for single or dual clock mode - I have not got a clue what this is for.

This leaves three pairs of connections: Dir-Direction, Pul - Pulse; and Enb -Enable.

This motor (and all that I have seen) has 200 steps. So as a circle is 360 degrees, A step is 360/200 degrees or 1 full step is 1.8 degrees. Finer steps can be taken dependent on the controller - mine goes to 25,600 micro-steps.

Enb is interesting. It is the last bit I used but is quite simple. Put 5V on Enb and the motor is disconnected (ie stops ata full step).

Dir defines which direction the motor rotates - I have left this alone for the moment.

Pulse is the next bit.so I used some code I found elsewhere:
Code: [Select]
` do {        digitalWrite(pin9PULSE, HIGH);        delayMicroseconds(mSecPulseInterval);                  digitalWrite(pin9PULSE, LOW);        delayMicroseconds(mSecPulseInterval)`

But nothing worked! So I will document what I should have done first.

Because this was experimental I needed to try various values and see what worked.

So I set up a loop of 0 to 500 in increments of 10 writing each value to the Serial port so I could see them on my PC.

Code: [Select]
`int i = 0;Serial.begin(9600);...void loop {i=i+10;if (i>500) {i=0;}Serial.print(i);Serial.print("\n");delay(500);}`

On the PC using the Arduino IDE (the programme in which you write your code) you need to have set the baud rate and the COM port. To check which COM port the Arduino is connected to you need to use Windows Device Manager.

Now one thing I found doing this is that The Arduino would regularly say the port is already in use or not available - when there should not have been a problem. I would love to know a better solution but unplugging the USB and sometimes resetting the Arduino (pushing the little button on the Arduino)  usually made it all work ok.

Note: I also came across a new programme failing to the Done Uploading - this was because I had accidentally changed the type of board.

Uploading this programme and clicking on the serial monitor button on the Arduino IDE should give a satisfyling list of numbers which we will use as the pulse interval..

Now a slight digression: originally I thought I would be clever and calculate the interval needed and my loop would be number of rotations per second. So when I got to printing on the serial port I had the number of rotations and the number of milliseconds interval. I was surprised to see this number going negative. I could explain why but just to say that if I wasn't printing the numbers I would not have realised.

Once I had got the list of numbers coming up I included some code to run the motor at the desired interval for three seconds.

Code: [Select]
`void loop {mSecPulseInterval=mSecPulseInterval+10;if (mSecPulseInterval>500) {mSecPulseInterval=0;}Serial.print(mSecPulseInterval);Serial.print("\n");delay(500);do {        digitalWrite(pin9PULSE, HIGH);        delayMicroseconds(mSecPulseInterval);                  digitalWrite(pin9PULSE, LOW);        delayMicroseconds(mSecPulseInterval)        } while (millis() < time +3000);      delay(500);`

Running this I got some nasty noises when mSecPulseInterval was below 50 or above 280 (I think) otherwise it seemed to be working. But over another cup of tea.

I realised that the documentation with the driver said that the Pul was triggered from the falling edge and that LOW must be at least 500 nSec (ie .5 microseconds. So I changed the code again to:

Code: [Select]
`void loop {mSecPulseInterval=mSecPulseInterval+10;if (mSecPulseInterval>300) {mSecPulseInterval=50;}Serial.print(mSecPulseInterval);Serial.print("\n");delay(500);do {        digitalWrite(pin9PULSE, HIGH);        delayMicroseconds(   1   );                  digitalWrite(pin9PULSE, LOW);        delayMicroseconds(mSecPulseInterval)        } while (millis() < time +3000);      delay(500);`

It is now working smoothly and to a point where I can make sense of it.

Next steps: change direction (pulse is on rising edge).
change microsteps switches.
Correct maths for calculating rotation.

Change code to allow a timing loop rather than using delayMicroseconds.

#### Robin2

#1
##### Sep 21, 2014, 10:58 am

It is impossible to know from the snippet how, for example, pin9PULSE is defined.

As a separate issue the variable pin9Pulse clearly represents a digital pin number (which may or may not be 9) and I think the code would be easier to follow if it was just called stepPin - resulting in digitalWrite(stepPin, HIGH).

You will probably find that this
Code: [Select]
`        digitalWrite(pin9PULSE, HIGH);        delayMicroseconds(mSecPulseInterval);                  digitalWrite(pin9PULSE, LOW);         delayMicroseconds(mSecPulseInterval)  `

can be simplified to this
Code: [Select]
`        digitalWrite(pin9PULSE, HIGH);                digitalWrite(pin9PULSE, LOW);         delayMicroseconds(mSecPulseInterval)  `

With a concurrent doubling of mSecPulseInterval. For most stepper drivers a very short high pulse is all that is required. And moving all of the time between steps (which governs speed) into a single place will make it much easier when you come to replace the use of delayMicroseconds() with the non-blocking technique in the Blink Without Delay example sketch.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

#### MarkT

#2
##### Sep 21, 2014, 12:55 pm
Normally a safe value to use for all stepper drivers on the market is 10us pulse time.

If the driver has high-speed opto coupler that pulsewidth can be much shorter.  If
the driver doesn't use an opto coupler (perhaps something like an A4988 breakout
board) then the pulse width can be much shorter.  Datasheets tell you these details,
always check them if you can.

The single/dual clock mode is about whether you have step/direction interface or
a forwards/backwards interface.

The default is step/direction - clocking pulses on the step pin, direction pin setup
to indicate which direction.

With dual clock the two pins are both clock pins, one to step forwards, one to step
backwards (and of course you must not step both together!).

Commercial stepper drivers always have an enable input and always use optocouplers.

The nice property of an opto coupler is you can drive it between pin and ground or
between pin and Vcc, which means you have a choice of polarity (active high or
active low).

Sometimes they have built-in resistors for the optocouplers, sometimes they don't,
you must read the datasheets as putting 5V across a bare optocoupler will blow it.
Most are sensible and have some resistance.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

#### Botolph

#3
##### Sep 21, 2014, 02:03 pm

Robin2 : I did remove the delay after the pulse and it works more smoothly.
MarkT: thanks for the explanation of dual clock.

I post my full working code with reversing included below.

Note the reason I use names such as pin8DIR (rather than pinDIR) is that is a double check on both my code and my wiring. If I was publishing generic code I would use pinDir but with so many other things to get wrong (and I must have got a lot of them) the naming just helps.

Code: [Select]
`/*Pul+ to Pin9Pul- to GNDDir+ to Pin8Dir- to GNDEnable+ 5V with push-to-make-switchEnable- GND*/const int pin9PULSE = 9;//set these next two for upper and lower limits for the test interval. The comments are from one motor I testedconst int intervalLow = 60;  //below 70 the motor screeches or vibrates but doesn't seem to moveconst int intervalHigh = 270; //above 260 the movement is not smoothconst int pin8DIR = 8;boolean IsDirHigh = false;unsigned long time;unsigned long iMain = 1000;unsigned long mSecPulseInterval = 0;void setup() {                  pinMode(pin8DIR, OUTPUT);     //direction pin  pinMode(pin9PULSE, OUTPUT); //step pin  digitalWrite(pin8DIR, LOW);  digitalWrite(pin9PULSE, LOW);    Serial.begin(9600);  //make sure serial monitor is on 9600 and COM port is set to the one being used}void loop() {      mSecPulseInterval =intervalLow;      do {     //=========================     Serial.print(" mSecPulseInterval ");     Serial.print(mSecPulseInterval);     Serial.print(" pin8DIR ");     Serial.print(digitalRead(pin8DIR));     Serial.print("\n ");       //digitalWrite(pin8DIR, LOW);       delay(200);   //theatrical pause      //=========================           time = millis();            do {        digitalWrite(pin9PULSE, HIGH);        //delayMicroseconds(1);                  digitalWrite(pin9PULSE, LOW);         delayMicroseconds(mSecPulseInterval)  ; //mSecPulseInterval);      } while (millis() < time +3000); //do this for 3 seconds      delay(500);                  mSecPulseInterval = mSecPulseInterval + 10;            //change direction      digitalWrite(pin8DIR, !digitalRead(pin8DIR));   } while (mSecPulseInterval < intervalHigh); }`

#### Robin2

#4
##### Sep 21, 2014, 05:43 pm
Code: [Select]
`const int pin9PULSE = 9;`

Another small point. For values below 255 using a byte rather than an int will save memory

And I should have said earlier, as some of your comments relate to the hardware you are using it would be useful to post links to the datasheets for the stepper motor and stepper motor driver board.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

#### Botolph

#5
##### Sep 21, 2014, 06:35 pm
Good point:

The drivers and motors can be found here: