Silly question - How to stop a stepper motor ?

am finally starting to experiment with stepper motors and have got the basics of moving them, but i must have missed some fundamental working because i don't know how to stop the motor (or more accurately, how to restart it from a 'stopped' position ?)

i started off with the thread by celem;
https://forum.arduino.cc/index.php?topic=85335

and then repurposed sample code from the tronix webpage;
http://www.4tronix.co.uk/arduino/Stepper-Motors.php

i now have a two-wheel stepperbot and am trying to control it with a Wii-Nunchuck.

my stumbling block is making it stop !

with the code below, when the joystick is in neutral position, the driver still functions and the wheels turn (slowly).

/* 
 * Nunchuck functions  -- Talk to a Wii Nunchuck
 * 2007-11 Tod E. Kurt, http://todbot.com/blog/
 *
 * The reading code originally from Windmeadow Labs
 *   http://www.windmeadow.com/node/42
 */

#include <Wire.h>                                                   //Include the Wire.h library so we can communicate with the Nunchuck

static uint8_t nunchuck_buf[6];   // array to store nunchuck data,

// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
static void nunchuck_init() {
  Wire.begin();                // join i2c bus as master
  Wire.beginTransmission(0x52);// transmit to device 0x52
  Wire.write((uint8_t)0x40);// sends memory address
  Wire.write((uint8_t)0x00);// sends sent a zero.
  Wire.endTransmission();// stop transmitting
}

// Send a request for data to the nunchuck
static void nunchuck_send_request() {
  Wire.beginTransmission(0x52);// transmit to device 0x52
  Wire.write((uint8_t)0x00);// sends one byte
  Wire.endTransmission();// stop transmitting
}


// Encode data to format that most wiimote drivers except?ACCEPT
// only needed if you use one of the regular wiimote drivers
static char nunchuk_decode_byte (char x)  {
  x = (x ^ 0x17) + 0x17;
  return x;
}

// Receive data back from the nunchuck,
// returns 1 on successful read. returns 0 on failure
static int nunchuck_get_data()  {
  int cnt = 0;
  Wire.requestFrom (0x52, 6);// request data from nunchuck
  while (Wire.available ()) {
    // receive byte as an integer
    nunchuck_buf[cnt] = nunchuk_decode_byte( Wire.read() );
    cnt++;
  }
  nunchuck_send_request();  // send request for next data payload
  // If we recieved the 6 bytes, then go print them
  if (cnt >= 5) {
    return 1;   // success
  }
  return 0; //failure
}

// returns value of x-axis joystick
static int nunchuck_joyx()  {
  return nunchuck_buf[0];
}

// returns value of y-axis joystick
static int nunchuck_joyy()  {
  return nunchuck_buf[1];
}

/// ABV=nunchuck_funcs.h

byte joyx, joyy, zbut, cbut;

////////////////////////////////////////////////

//declare variables for the motor pins
const byte motRGpin1 = 2;  // Blue   - 28BYJ48 pin 1
const byte motRGpin2 = 3;  // Pink   - 28BYJ48 pin 2
const byte motRGpin3 = 4; // Yellow - 28BYJ48 pin 3
const byte motRGpin4 = 5; // Orange - 28BYJ48 pin 4
				// Red    - 28BYJ48 pin 5 (VCC)
const byte motLFpin1 = 9;  // Blue   - 28BYJ48 pin 1
const byte motLFpin2 = 8;  // Pink   - 28BYJ48 pin 2
const byte motLFpin3 = 7; // Yellow - 28BYJ48 pin 3
const byte motLFpin4 = 6; // Orange - 28BYJ48 pin 4

int motorSpeed = 1200;     //variable to set stepper speed
byte lookup[8] = {B01000, B01100, B00100, B00110, B00010, B00011, B00001, B01001};

byte count = 0;

///////////////////////////////////////////////////////////////////////////

void setup() {
  //declare the motor pins as outputs
  pinMode(motRGpin1, OUTPUT);
  pinMode(motRGpin2, OUTPUT);
  pinMode(motRGpin3, OUTPUT);
  pinMode(motRGpin4, OUTPUT);
  pinMode(motLFpin1, OUTPUT);
  pinMode(motLFpin2, OUTPUT);
  pinMode(motLFpin3, OUTPUT);
  pinMode(motLFpin4, OUTPUT);

  Serial.begin(9600);
  nunchuck_init();
}

void loop() {
  nunchuck_get_data();
  joyx = nunchuck_joyx();    // ranges from approx 36 - 233 : MDL 137-8
  joyy = nunchuck_joyy();    // ranges from approx 33 - 215 : MDL 131

  if (((joyy < 200)&&(joyy > 50)) && ((joyx < 200)&&(joyx > 50))) {
//          Serial.println("joystick neutral");
  //  BOTHoff();
/*    
    DBLoutputDIFF(count);
    delay(50);  // pseudoSTOP...
    count++;
    if (count > 7) count = 0;
*/

  } else {

    if (joyy >= 200) {   
      //    Serial.println("joyy UP");      
      DBLoutputSAME(count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

    if (joyy <= 50) {
      //    Serial.println("joyy DOWN");
      DBLoutputSAME(7-count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

    if (joyx >= 200) {
      //    Serial.println("joyx UP");      
      DBLoutputDIFF(count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

    if (joyx <= 50) {
      //    Serial.println("joyx DOWN");
      DBLoutputDIFF(7-count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

  }

}

//////////////////////////////////////////////////////////////////////////////

void DBLoutputSAME(byte out)  {
  digitalWrite(motRGpin1, bitRead(lookup[out], 0));
  digitalWrite(motLFpin1, bitRead(lookup[out], 3));

  digitalWrite(motRGpin2, bitRead(lookup[out], 1));
  digitalWrite(motLFpin2, bitRead(lookup[out], 2));

  digitalWrite(motRGpin3, bitRead(lookup[out], 2));
  digitalWrite(motLFpin3, bitRead(lookup[out], 1));

  digitalWrite(motRGpin4, bitRead(lookup[out], 3));
  digitalWrite(motLFpin4, bitRead(lookup[out], 0));
}

void DBLoutputDIFF(byte out)  {
  digitalWrite(motRGpin1, bitRead(lookup[out], 0));
  digitalWrite(motLFpin1, bitRead(lookup[out], 0));
  digitalWrite(motRGpin2, bitRead(lookup[out], 1));
  digitalWrite(motLFpin2, bitRead(lookup[out], 1));
  digitalWrite(motRGpin3, bitRead(lookup[out], 2));
  digitalWrite(motLFpin3, bitRead(lookup[out], 2));
  digitalWrite(motRGpin4, bitRead(lookup[out], 3));
  digitalWrite(motLFpin4, bitRead(lookup[out], 3));
}

void BOTHoff()  {
  digitalWrite(motRGpin1, LOW);
  digitalWrite(motLFpin1, LOW);
  digitalWrite(motRGpin2, LOW);
  digitalWrite(motLFpin2, LOW);
  digitalWrite(motRGpin3, LOW);
  digitalWrite(motLFpin3, LOW);
  digitalWrite(motRGpin4, LOW);
  digitalWrite(motLFpin4, LOW);
}

but if i activate (uncomment) the BOTHoff() function, nothing happens - presumably it is in the 'off' state, but then the 'move' functions don't work.

using just the Serial.println lines for debugging confirms the logic works as far as the joystick goes.

Thanks for anyone pointing what might be painfully obvious in hindsight...

EDIT:
FWIW-
this is the motor and driver being used;

These links may help
Stepper Motor Basics
Simple Stepper Code

In very simple terms you stop a stepper motor by not sending it any step signals.

...R

Robin2:
These links may help

uhm, thanks - but those are for the Pololu drivers and bipolar steppers.

i'm using the "simpler(basic?)" ULN2003 drivers with those cheap eBay 5-wire unipolar steppers.

they really seem simple to rotate/move/turn - just keep cycling through the sequential electrical polarities via the windings - albeit with blocking code of delayMicroseconds - ie.

void step1()  {
  digitalWrite(motPin1, LOW);
  digitalWrite(motPin2, HIGH);
  digitalWrite(motPin3, HIGH);
  digitalWrite(motPin4, LOW);
}

void step2()  {
  digitalWrite(motPin1, LOW);
  digitalWrite(motPin2, LOW);
  digitalWrite(motPin3, HIGH);
  digitalWrite(motPin4, LOW);
}

void step3()  {
  digitalWrite(motPin1, LOW);
  digitalWrite(motPin2, LOW);
  digitalWrite(motPin3, HIGH);
  digitalWrite(motPin4, HIGH);
}

etc....

so, i must be missing something even more basic.

Robin2:
In very simple terms you stop a stepper motor by not sending it any step signals.

which is what is baffling me, because not sending any signals still results in the motor moving... ?

OK - i've stopped it !

possibly a quirk of the driver circuit ?

it was a matter of "pulsing" the stop/off signal.

instead of a simple BOTHoff();

it had to have a delayMicrosecond() in between.

strange... but that solved the problem.

would still appreciate why that is though, why and how(!) is an 'off' (digitalWrite,LOW) different from the exact same function with a delay in between repeating the same instruction ?

Please post your full code.

which is what is baffling me, because not sending any signals still results in the motor moving... ?

No, you must have been sending pulses if it was moving.

MarkT:
Please post your full code.

i did, here it is again, but just the main section (setup & loop) without the nunchuck functions;

////////////////////////////////////////////////

//declare variables for the motor pins
const byte motRGpin1 = 2;  // Blue   - 28BYJ48 pin 1
const byte motRGpin2 = 3;  // Pink   - 28BYJ48 pin 2
const byte motRGpin3 = 4; // Yellow - 28BYJ48 pin 3
const byte motRGpin4 = 5; // Orange - 28BYJ48 pin 4
				// Red    - 28BYJ48 pin 5 (VCC)
const byte motLFpin1 = 9;  // Blue   - 28BYJ48 pin 1
const byte motLFpin2 = 8;  // Pink   - 28BYJ48 pin 2
const byte motLFpin3 = 7; // Yellow - 28BYJ48 pin 3
const byte motLFpin4 = 6; // Orange - 28BYJ48 pin 4

int motorSpeed = 1200;     //variable to set stepper speed
byte lookup[8] = {B01000, B01100, B00100, B00110, B00010, B00011, B00001, B01001};

byte count = 0;

///////////////////////////////////////////////////////////////////////////

void setup() {
  //declare the motor pins as outputs
  pinMode(motRGpin1, OUTPUT);
  pinMode(motRGpin2, OUTPUT);
  pinMode(motRGpin3, OUTPUT);
  pinMode(motRGpin4, OUTPUT);
  pinMode(motLFpin1, OUTPUT);
  pinMode(motLFpin2, OUTPUT);
  pinMode(motLFpin3, OUTPUT);
  pinMode(motLFpin4, OUTPUT);

  Serial.begin(9600);
  nunchuck_init();
}

void loop() {
  nunchuck_get_data();
  joyx = nunchuck_joyx();    // ranges from approx 36 - 233 : MDL 137-8
  joyy = nunchuck_joyy();    // ranges from approx 33 - 215 : MDL 131

  if (((joyy < 200)&&(joyy > 50)) && ((joyx < 200)&&(joyx > 50))) {
//          Serial.println("joystick neutral");
  //  BOTHoff();

  } else {

    if (joyy >= 200) {   
      //    Serial.println("joyy UP");     
      DBLoutputSAME(count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

    if (joyy <= 50) {
      //    Serial.println("joyy DOWN");
      DBLoutputSAME(7-count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

    if (joyx >= 200) {
      //    Serial.println("joyx UP");     
      DBLoutputDIFF(count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

    if (joyx <= 50) {
      //    Serial.println("joyx DOWN");
      DBLoutputDIFF(7-count);
      delayMicroseconds(1200);
      count++;
      if (count > 7) count = 0;
    }

  }

}

//////////////////////////////////////////////////////////////////////////////

void DBLoutputSAME(byte out)  {
  digitalWrite(motRGpin1, bitRead(lookup[out], 0));
  digitalWrite(motLFpin1, bitRead(lookup[out], 3));

  digitalWrite(motRGpin2, bitRead(lookup[out], 1));
  digitalWrite(motLFpin2, bitRead(lookup[out], 2));

  digitalWrite(motRGpin3, bitRead(lookup[out], 2));
  digitalWrite(motLFpin3, bitRead(lookup[out], 1));

  digitalWrite(motRGpin4, bitRead(lookup[out], 3));
  digitalWrite(motLFpin4, bitRead(lookup[out], 0));
}

void DBLoutputDIFF(byte out)  {
  digitalWrite(motRGpin1, bitRead(lookup[out], 0));
  digitalWrite(motLFpin1, bitRead(lookup[out], 0));
  digitalWrite(motRGpin2, bitRead(lookup[out], 1));
  digitalWrite(motLFpin2, bitRead(lookup[out], 1));
  digitalWrite(motRGpin3, bitRead(lookup[out], 2));
  digitalWrite(motLFpin3, bitRead(lookup[out], 2));
  digitalWrite(motRGpin4, bitRead(lookup[out], 3));
  digitalWrite(motLFpin4, bitRead(lookup[out], 3));
}

void BOTHoff()  {
  digitalWrite(motRGpin1, LOW);
  digitalWrite(motLFpin1, LOW);
  digitalWrite(motRGpin2, LOW);
  digitalWrite(motLFpin2, LOW);
  digitalWrite(motRGpin3, LOW);
  digitalWrite(motLFpin3, LOW);
  digitalWrite(motRGpin4, LOW);
  digitalWrite(motLFpin4, LOW);
}

MarkT:
No, you must have been sending pulses if it was moving.

i certainly wasn't doing it intentionally, and i can't see where i am doing it if it is.

BabyGeezer:
i certainly wasn't doing it intentionally, and i can't see where i am doing it if it is.

At this stage of your leaning I reckon it would make things much clearer for you if you use the Stepper or AccelStepper libraries as they take care of all the details of which I/O pin to change to make the motor move.

uhm, thanks - but those are for the Pololu drivers and bipolar steppers.

As far as I can see you added the picture of the 28byj motor after I posted Reply #1 :slight_smile: In any case, while the code will be a little different all stepper motors work on the same general principles.

...R

BabyGeezer:
i certainly wasn't doing it intentionally, and i can't see where i am doing it if it is.

Then I suggest restructuring the code so you can understand it. All the stepper driving stuff should
be separated out from everything else, and have clearly named functions so you know what it
does without having to read lots of complicated code.

Look at the Stepper and AccelStepper libraries for the sort of operations you'd expect from
stepper motor primitives... 'DBLoutputSAME' doesn't seem very clear to me...

thank you for your patience and continued response.

MarkT:
Look at the Stepper and AccelStepper libraries for the sort of operations you'd expect from
stepper motor primitives... 'DBLoutputSAME' doesn't seem very clear to me...

i did try to understand those codes, but i believe the code i'm using is much simpler, albeit (or because it is) blocking code.

the naming of DBLoutputSAME "evolved" from the original code from the Tronix website which was setOutput() - i had conbined two motors into the one function since it seemed more straightforward than calling the same function for two different motors separately.

"SAME" meant the pin sequencing was for both wheels rotating in the same direction (ie. for forward or backwards motion) and "DIFF", for opposing rotation, ie. to pivot either left (counter-clockwise) or right (clockwise).

MarkT:
Then I suggest restructuring the code so you can understand it. All the stepper driving stuff should
be separated out from everything else, and have clearly named functions so you know what it
does without having to read lots of complicated code.

i have now further simplified the code as pseudo-code as i understand it, (in CAPS, sorry if that makes it like shouting, can't use bold in the code tags).

maybe that might bridge/highlight the gap in my understanding of what i think is happening and what actually is.

void loop() {

// READ IN THE JOYSTICK DATA
  nunchuck_get_data();
  joyx = nunchuck_joyx();    // ranges from approx 36 - 233 : MDL 137-8
  joyy = nunchuck_joyy();    // ranges from approx 33 - 215 : MDL 131

// IF JOYSTICK NEUTRAL - DO NOTHING
  if (((joyy < 200)&&(joyy > 50)) && ((joyx < 200)&&(joyx > 50))) {
//          Serial.println("joystick neutral");
  //  BOTHoff();

  } else {

// ELSE - CALL APPROPRIATE MOVE FUNCTIONS ACCORDING TO THE JOYSTICK POSITION
    if (joyy >= 200) {   
      DBLoutputSAME(count); ==> forwards
    }

    if (joyy <= 50) {
      DBLoutputSAME(7-count); ==> backwards
    }

    if (joyx >= 200) {
      DBLoutputDIFF(count); ==> turn right
    }

    if (joyx <= 50) {
      DBLoutputDIFF(7-count); ==> turn left
    }

  }

}

what does happen with the above code is that the vehicle moves as expected according to each of the four joystick extreme positions, except when in neutral - it moves in an apparently default direction (pivoting, ie. both motors rotating in the same direction with respect to itself).

i stumbled on a crude fix by "pulsing" the BOTHoff() function - ie. adding a delayMicroseconds(1200); in the sequence - and this actually resulted in the driver stopping the stepper motors.

maybe i should be asking this in the Programming section because it might actually have more to do with the execution sequence of the instructions - although it does seem to be related to code specific to the stepper programming.