DF Robot Shop Motor Commands

I'm playing around with the rover kit from DF Robot Shop (http://www.robotshop.com/productinfo.aspx?pc=rb-rbo-33). I'm running the code essentially as described in the rover's instruction manual.

I notice that when I give the command for the rover to turn right or left, it spins around in clockwise or counterclockwise circles, respectively. Rather than spinning around endlessly, I really want it to spin 30 degrees left or right, stop, and wait for the next command.

The kit comes with what look like pretty basic 5V DC motors. I think I need to re-write the code so that the motors only spin for 300 or 400 milliseconds before stopping and waiting for the next command. I'm not sure how to do that. I've looked at some of the "timer" libraries on the Arduino forum but they dont' really appear to be what I'm looking for.

Here's the code I'm running. Any general suggestions would be great!

//Control the Rover with four over-serial commands: left, right, forward, backwards.
//Modified the forward, left, right and backward commands to make the rover go
//in the desired direction.

int E1 = 6; //M1 Speed Control
int E2 = 5; //M2 Speed Control
int M1 = 8; //M1 Direction Control
int M2 = 7; //M2 Direction Control

void setup (void)
{
int i;
for(i=5;i<=8;i++)
pinMode(i, OUTPUT);
Serial.begin(9600);
}

void loop(void)
{
while (Serial.available() < 1) {} // Wait until a character is received
char val = Serial.read();
int leftspeed = 250; //255 is maximum speed
int rightspeed = 255;
switch(val) // Perform an action depending on the command
{
case 'f'://Move Forward
forward (leftspeed,rightspeed);
break;
case 'b'://Move Backwards
reverse (leftspeed,rightspeed);
break;
case 'l'://Turn Left
left (leftspeed,rightspeed);
break;
case 'r'://Turn Right
right (leftspeed,rightspeed);
break;
default:
stop();
break;
case 's'://stop
halt (leftspeed,rightspeed);
break;
}
}

void stop (void) //Stop
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}

void forward(char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite(E2,b);
digitalWrite(M2,HIGH);
}

void reverse (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite(E2,b);
digitalWrite(M2,LOW);
}

void left (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}

void right (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}

void halt (char a,char b)
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}

Rather than spinning around endlessly, I really want it to spin 30 degrees left or right

Not possible without some form of feedback to know how much the heading has changed.

I think I need to re-write the code so that the motors only spin for 300 or 400 milliseconds before stopping and waiting for the next command.

That's a different story. Only with experimenting on one kind of surface will you know how long to turn to achieve some change in heading.

I've looked at some of the "timer" libraries on the Arduino forum but they dont' really appear to be what I'm looking for.

You need to know when you started a turn (using millis() to record when the turn started), and turn while now (use millis(), again) minus then (when the turn started) is less than some value.

Thanks, I'll give that a shot.

If that doesn't work, you might try adjusting the speed of the motors instead of how long the motors run for.

Up in the void loop you initiate the speed of both motors. Interestingly, the left motor is set at speed 250 out of 255 and the right motor is set at 255 out of 255. So if I'm reading this correctly, your right motor is moving faster than the left motor. Not sure if that's intentional because of the chassis, or it your robot is running in circles.

int leftspeed = 250; //255 is maximum speed
int rightspeed = 255;

So what you could do to alter the speed is change leftspeed = [value] and rightspeed = [value] in the switch/case statements.

switch(val) // Perform an action depending on the command
  {
    case 'f'://Move Forward
     leftspeed = 255;
     rightspeed = 255;
     forward (leftspeed,rightspeed);
     break;
    case 'b'://Move Backwards
     leftspeed = 255;
     rightspeed = 255;
     reverse (leftspeed,rightspeed);
     break;
    case 'l'://Turn Left
     leftspeed = 150;    //play with these 150 values until your robot only turns 30 degrees during it's turn left and turn right commands
     rightspeed = 150;  //play with these 150 values until your robot only turns 30 degrees during it's turn left and turn right commands
     left (leftspeed,rightspeed);
     break;
    case 'r'://Turn Right
     leftspeed = 150;    //play with these 150 values until your robot only turns 30 degrees during it's turn left and turn right commands
     rightspeed = 150;  //play with these 150 values until your robot only turns 30 degrees during it's turn left and turn right commands
     right (leftspeed,rightspeed);
     break;
    default:
     stop();
     break;
    case 's'://stop
     halt (leftspeed,rightspeed);
     break;
  }
     leftspeed = 255
     rightspeed = 255

The compiler and I would like if you used semicolons here... (and there...)

^true that... I always do that and get compiling errors.

ALWAYS

I fixed the offending post, but PaulS was right.

@ PaulS-

I tried adding another "while" statement incorporating millis() to make the rover stop turning left after 300 milliseconds. I eventually got the compiler to run through the code without errors, but the rover doesn't actually behave differently. It still turns in endless counter-clockwise circles. I think I need some way to start the millis() counter once I send the "left" command over the serial port.

Here's my code below:

@ Schmidtn

Thanks for your suggestion about the motor speed. I do have the motors set at different speeds. They are pretty cheap and the rover tends to turn right when both motors are running at full speed. I set the left speed motor a bit slower so that the rover basically goes straight in the forwards and backwards modes.

//Control the Rover with four over-serial commands: left, right, forward, backwards.
//Modified the forward, left, right and backward commands to make the rover go
//in the desired direction.

int E1 = 6; //M1 Speed Control
int E2 = 5; //M2 Speed Control
int M1 = 8; //M1 Direction Control
int M2 = 7; //M2 Direction Control

void setup (void)
{
int i;
for(i=5;i<=8;i++)
pinMode(i, OUTPUT);
Serial.begin(9600);
}

void loop(void)
{
while (Serial.available() < 1) {} // Wait until a character is received
char val = Serial.read();
int leftspeed = 250; //255 is maximum speed
int rightspeed = 255;
switch(val) // Perform an action depending on the command
{
case 'f'://Move Forward
forward (leftspeed,rightspeed);
break;
case 'b'://Move Backwards
reverse (leftspeed,rightspeed);
break;
case 'l'://Turn Left
left (leftspeed,rightspeed);
break;
case 'r'://Turn Right
right (leftspeed,rightspeed);
break;
default:
stop();
break;
case 's'://stop
halt (leftspeed,rightspeed);
break;
}
}

void stop (void) //Stop
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}

void forward(char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite(E2,b);
digitalWrite(M2,HIGH);
}

void reverse (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite(E2,b);
digitalWrite(M2,LOW);
}

void left (char a,char b)
{
int x = millis();

while (x < 300)

{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}

}
void right (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}

void halt (char a,char b)
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}

I think I need some way to start the millis() counter once I send the "left" command over the serial port.

No. I can assure you that you do not need to restart the millis() counter. If you call your girlfriend (or boyfriend) and she/he says call me back in an hour, do you need to reset your watch? No, of course not. You simply note the current time. At many points in the future, you check the current time, and see if "now" minus "then" is greater to or equal to an hour. If so, you make the call again.

void left (char a,char b)
{
  int x = millis();
 
  while (x < 300)

{
  analogWrite (E1,a);
  digitalWrite(M1,LOW);
  analogWrite (E2,b);
  digitalWrite(M2,HIGH);
}

}

First off, millis() does not return an int. It returns an unsigned long. After the Arduino has been running for 32.7+ seconds, the output from millis() will overflow an int.

Something like this might work:

void left(char a, char b)
{
  // Note the time
  unsigned long turnStart = millis();

  // Start the turn
  analogWrite (E1,a);
  digitalWrite(M1,LOW);
  analogWrite (E2,b);
  digitalWrite(M2,HIGH);

  // Diddle for 300 milliseconds
  while(millis() - turnStart < 300)
  {
     // Don't do a thing...
  }

  // Stop turning
  analogWrite (E1,0);
  digitalWrite(M1,LOW);
  analogWrite (E2,0);
  digitalWrite(M2,LOW);
}

Thanks PaulS, this code you provided works perfectly!