Serial commands - A tiny bit of help needed!

Hello everyone,

I’m trying to control a stepper motor via serial commands.

My code looks like this ATM:

#include <Stepper.h>

Stepper myStepper = Stepper(48, 2, 3, 4, 5);
int value;


void setup()
{
Serial.begin(9600);
}

void loop()
{
if (Serial.available() > 0) {
  value = 0;
  while(Serial.available() > 0)
  {
    value *= 10;
    value += (Serial.read() - '0');
    delay(1);
  }
  
  Serial.println(value);
  
      myStepper.setSpeed(10);
      myStepper.step(value);
      Serial.flush();
  }
}

While I can control “forward” movements perfectly (eg. I send “10” to the serial monitor and the stepper moves 10 steps forward), I can’t control it with negative values - if i put steps(-10) in the code it goes 10 steps backwards, but if I send -10 in the serial monitor, it doesn’t work.

Any hint about getting it to work?

Thanks!

Seb

I'm not sure what you are driving into but most steppers use step and direction as two separate signals. The hardware somehow has to interpret -ve for a change direction.

Your code isn't looking for a minus sign in the incoming serial data.

Andrew

Your code isn't looking for a minus sign in the incoming serial data.

Worse than that, it's assuming that every byte received represents a digit.

Sebastion: How would your stepper motor react if you entered "Fred" in the serial monitor, and hit send?

Thanks guys!

First, Marsheng: It's an unipolar motor driven directly by a Darlington array (ULN2003), so there are 4 pins for the coils and a pin for 5V.

PaulS: I tried with Fred - guess the result: 29182 steps (or at least this is the number that I got printed in the serial monitor).

I'm quite new to programming, so if anyone could help me, I'll appreciate it. Even if it means rewriting everything from scratch :)

Thanks!

Seb

You are assuming, with this statement:

    value += (Serial.read() - '0');

that the byte returned by Serial.read() is in the range ‘0’ to ‘9’.

As Ronald Reagan used to say, you need to trust AND verify:

char aByte = Serial.read();
if(aByte >= '0' && aByte <= '9')
  value += aByte - '0';

This will handle input like “Fred”.

To handle negative numbers and Fred:

  boolean negative = false;
  value = 0;
  while(Serial.available() > 0)
  {
    byte aChar = Serial.read();
    if(aChar == '-')
      negative = true;
    else if(aChar >= '0' && aChar <= '9')
    {
      value *= 10;
      value += aChar - '0';
      delay(1);
    }
  }
  if(negative)
    value += -1;

To be thorough, if a non-digit is found after a digit or minus sign is found, processing of the number should stop. Thus, -100Dean could be handled, as well as -10-129g.

Thanks PaulS!

We’re almost there… just not quite yet.

That’s my code right now (I modified the delays a bit, 1 milli looks to be too quick, I guess the board was unable to receive the full command and stopped somewhere in between):

#include <Stepper.h>

Stepper myStepper = Stepper(48, 2, 3, 4, 5);
int value;


void setup()
{
Serial.begin(9600);
}

void loop()
{
if (Serial.available() > 0) {
  boolean negative = false;
  value = 0;
  while(Serial.available() > 0)
  {
    byte aChar = Serial.read();
    if(aChar == '-')
      negative = true;
    else if(aChar >= '0' && aChar <= '9')
    {
      value *= 10;
      value += aChar - '0';
      delay(100);
    }
  }
  if(negative)
    value += -1;   
      myStepper.setSpeed(100);
      myStepper.step(value);      
      Serial.flush();
  }
}

Now… If I write a negative value (eg. -12) the stepper does one step backwards and 12 steps forward… I guess the trick is somewhere in the line

    value += -1;

Correct me if I’m wrong, even though I have no idea what to do to fix it :slight_smile:

Thanks again,

S.

Oops. If the negative flag is set, we want to multiply the value by -1, not add -1.

value *= -1;

Hmm, funny... now it does spin by X steps, but always forward, no matter if it's a negative or positive value... :-?

You need to change the scope of your boolean "negative" to global - you're resetting it every time through your loop.

Like this?

#include <Stepper.h>

Stepper myStepper = Stepper(48, 2, 3, 4, 5);
unsigned int value;


void setup()
{
Serial.begin(9600);
}

void loop()
{
if (Serial.available() > 0) {
  boolean global = false;
  value = 0;
  while(Serial.available() > 0)
  {
    byte aChar = Serial.read();
    if(aChar == '-')
      global = true;
    else if(aChar >= '0' && aChar <= '9')
    {
      value *= 10;
      value += aChar - '0';
      delay(100);
    }
  }
  if(global)
    value *= -1;   
      myStepper.setSpeed(100);
      myStepper.step(value);      
      Serial.flush();
  }
}

If you meant that… it still spins only in one direction… I’m getting frustrated :smiley:

Global means that you declare the variable outside the loop or setup section.

I think that it would be better as a static variable.

this means that you declare it as: static boolean negative = false;

#include <Stepper.h>

Stepper myStepper = Stepper(48, 2, 3, 4, 5);
int value;
static boolean negative = false;

void setup()
{
Serial.begin(9600);
}

void loop()
{
if (Serial.available() > 0) {
  value = 0;
  while(Serial.available() > 0)
  {
    byte aChar = Serial.read();
    if(aChar == '-')
      negative = true;
    else if(aChar >= '0' && aChar <= '9')
    {
      value *= 10;
      value += aChar - '0';
      delay(100);
    }
  }
  if(negative)
    value *= -1;   
      myStepper.setSpeed(100);
      myStepper.step(value);      
      Serial.flush();
  }
}

Done, but it still turns only forward, no matter if there’s a - sign or no… :stuck_out_tongue:

If you Serial.print(value), do you get the correct (negative, as appropriate) number?

Does calling Stepper::step() with a negative number actually result in stepping in the negative direction? A quick peak at the code suggests that it should.

Ok, so... I sent the following commands:

Command: -12 Serial monitor: 0-12 Command: 12 Serial monitor: 0-12-12

I also tried first sending the positive and then the negative:

Command 12 Serial monitor: 12 Command: -12 Serial monitor: 120-12

So I guess there are problems in the conversion of the values... any hint?

Seb

Without seeing how and where you print data to the serial monitor, I'm only going to be able to ask some questions.

Why is negative declared static? It should not be. It should also be initialized to false when value is set to 0. Or, have it as a local variable in loop().

Some judicial use of Serial.println() or Serial.print("value = ") might be in order.

I hope that you weren't actually sending the word "command" before the number.

It may pay to put this before the "myStepper.step(value);" code:

Serial.println(value, DEC); //see what the value of "value" is
for( ; ; );                          //loop forever (stop program here).

See if the value of "value" is what you expect.

Using Serial.print for debugging is very useful.

The "for( ; ; );" statement isn't really necessary, but I usually put it in just in case is sends something too stupid to the hardware I'm using.

Do lots of (serial) tests on different things, and tell us what you get.

:)

Ok, I have some minor news :slight_smile:

here’s my actual code:

#include <Stepper.h>

Stepper myStepper = Stepper(48, 2, 3, 4, 5);
int value;
boolean negative = false;

void setup()
{
Serial.begin(9600);
}

void loop()
{
if (Serial.available() > 0) {
  value = 0;
  while(Serial.available() > 0)
  {
    byte aChar = Serial.read();
    if(aChar == '-')
      negative = true;
    else if(aChar >= '0' && aChar <= '9')
    {
      value *= 10;
      value += aChar - '0';
      delay(100);
    }
  }
  if(negative)
    value *= -1;   
      myStepper.setSpeed(100);
      myStepper.step(value);
      Serial.print(value);
      Serial.print("\n");
      Serial.flush();
  }
}

What I noticed are the following things:

  • If I start with a forward motion (e.g. command: 48) it spins forward and keeps spinning forward as long as I give it positive commands;
  • once I send a negative command (e.g. -12), it spins 12 steps BACKWARD! YAY! :smiley: But…
  • Once I sent a negative command, anything I write in the Serial monitor becomes negative, no matter what I write, so it spins only forward.

Also, I noticed two more things:

  • The first command is ignored. All following commands sent via the Serial monitor are fine.
  • When I send a negative command, it prints a 0 before my actual negative number. For example:

12 ← positive command - spins 12st forward
48 ← positive command - spins 48st forward
0 ← mysterious zero
-48 - negative command sent BEFORE the zero appeared - spins 48st backwards
-48 - positive command sent, negative command printed and executed (spins 48st backwards)

So, I guess it somehow remembers that minus sign and keeps using it. I think all I need is some way to flush it… but obviously, the Serial(flush) doesn’t work. Any idea? Also, any idea why the first command after power up keeps being ignored?

Thanks,

Seb

The fact that directions remain negative after a negative value is received is because you never reset negative to false. In my example, negative was a local variable (declared inside the loop function) and was re-initialized on every pass through loop.

The delay(100) after a character is stored in the array, which only happens when the character is a digit shouldn't be required.

You might want to add an end-of-packet marker (; maybe) so that sending the characters -120 does not end up getting interpreted as -1 and 20. You'd add another boolean, packetEnded, initially set to false, that was set to true when the end of packet marker was encountered. Then, move the stepper motor only when packetEnded was true (and only reset value then, too).

Don't flush the serial buffer. Unless you know why you are doing it, and exactly what it does, don't do it.

The "mysterious" 0 may be happening because there is do pause after reading the - from the serial buffer, and the rest of the number hasn't arrived yet. Getting data from the serial buffer is much faster than getting data into the serial buffer. Adding the end-of-packet marker mentioned earlier will stop this from happening.

Thanks Paul,

could you (when you'll have the time to, of course) please (pretty please with sugar on top) write me some code? I'm really still learning so if I'd start trying to translate your words into code, I'm sure I'd end up doing a mess :P

Thank you again and again and again :)

Seb