Motor control without delay

Below is the code for my serial motor control, but I think the motors don't run long enough to move forward. And if I use a delay it runs long after I release the button that is transmitting to the serial port. Can I fix my code to be more responsive? Something using the timer maybe, I found http://www.instructables.com/answers/How-to-write-code-for-an-Arduino-with-the-Arduino-/, but Im not sure if its what I need to do to solve the problem.

#define LeftMotorPWM 11
#define RightMotorPWM 6
#define LeftMotorDIR 3
#define RightMotorDIR 5

#include <SoftwareSerial.h>
SoftwareSerial softSerialOne(12, 255);

int speed = 128;

void setup()
{
  pinMode(LeftMotorDIR, OUTPUT);
  pinMode(LeftMotorPWM, OUTPUT);
  pinMode(RightMotorDIR, OUTPUT);
  pinMode(RightMotorPWM, OUTPUT);
  Serial.begin(9600);
  softSerialOne.begin(9600);
}

void loop()
{
  if (softSerialOne.available() > 0)
  {
    softSerialOne.listen();
    char inByte=softSerialOne.read();
    Serial.write(inByte);
    switch (inByte) 
    {
    case 'j8':    
      Serial.println ("Move Forward");
      analogWrite(LeftMotorPWM,speed);
      digitalWrite(LeftMotorDIR,LOW);
      analogWrite(RightMotorPWM,speed);
      digitalWrite(RightMotorDIR,LOW);
      break;
    case 'j2':    
      Serial.println ("Move Back");
      analogWrite(LeftMotorPWM,0);
      analogWrite(LeftMotorDIR,speed);
      analogWrite(RightMotorPWM,0);
      analogWrite(RightMotorDIR,speed);
      break;
    case 'j4':    
      Serial.println ("Move Left");
      analogWrite(LeftMotorPWM,0);
      analogWrite(LeftMotorDIR,speed);
      analogWrite(RightMotorPWM,speed);
      analogWrite(RightMotorDIR,0);
      break;
    case 'j6':    
      Serial.println ("Move Right");
      analogWrite(LeftMotorPWM,speed);
      analogWrite(LeftMotorDIR,0);
      analogWrite(RightMotorPWM,0);
      analogWrite(RightMotorDIR,speed);
      break;
    default: // stop, just to be safe
      analogWrite(LeftMotorPWM,0);
      analogWrite(LeftMotorDIR,0);
      analogWrite(RightMotorPWM,0);
      analogWrite(RightMotorDIR,0);
    break;
    }
  } 
}

houareau:

    case 'j8':    

case 'j2':   
    case 'j4':   
    case 'j6':

Where do these commands come from? As far as I know the Arduino's compiler doesn't use MBCS so I don't know what these character literals would produce.

The commands come from a java console app it outputs those commands eg. j8 when a numpad button is pressed for direction and the servo sliders in the app output something like s255.

I have attached the original arduino code. I couldn't get it to run properly though, since I changed the motor controller the motors don't stop when they should so I have been trying to break it down and rewrite it.

here is the link to my previous question http://arduino.cc/forum/index.php/topic,138018.0.html

original.ino (5.61 KB)

What output are you getting in the terminal monitor?

j8Move Forward

j2Move Back

j4Move Left

j6Move Right

Is that what you meant?

That's what I meant, but now, like PeterH, I'm baffled as to what's going on with those character constants like 'j8'. Given that the move messages are being printed though, I assume the motors are being commanded also. If you remove the default case, which seems to be the only way the motors are turned off, do the motors keep running?

Yes they do...

Your output shows an additional blank line after the move data. I wonder if your java app is sending a CR or LF after the command bytes. If so, it'll immediately invoke the default state and stop. It seems clear that the default is being called, but it might be nice to put it back and prove it with a serial.print of its own.

Here is what I get with the println ("Stopped"); on default.

jStopped
6Move Right

Stopped

It appears to me that your java app is sending a series of bytes: 'j' '8' and CR or LF. The funky 'j8' characters you're using in the case statements don't exist, although why it works is a mystery. To test this theory, change your existing case statements and remove the j so that e.g. case 'j8' becomes case '8'.

Add a case for 'j' that does nothing - don't forget a break though. Similarly for '\n' and 'r'. You could combine these with fall-through if you like.

I'd expect the motors to stay on now, because the default stop will be avoided. Testing will tell though.

Aah yes, if I change the case statements to just "j" or "8" is still runs, I think I need to do something more like the code below, but fine in one direction, but keep spinning in the other.

// Firmware for the Android Shield Board for tank robots
// Pan/tilt servos now work: 0 pin off, 255 pin on, 1~254 8 bit granularity servo movement (5 microseconds).
#define PwmPinMotorA 11
#define PwmPinMotorB 6
#define DirectionPinMotorA 3
#define DirectionPinMotorB 5
#define ServoPin1 0
#define ServoPin2 0
#define ServoFlip1 false
#define ServoFlip2 false

#define mySerialSpeed 9600 // arduino 2009: 4800 or lower!
#define debugSerialSpeed 9600 // arduino 2009: 4800 or lower!
#define BufferLength 16
#define LineEnd1 13
#define LineEnd2 10
#define ServoTimingStep 5
#define ServoCenter 1500
#define ServoTimingFloor ServoCenter-(127*ServoTimingStep)

//#define serialout
#define debugout

#include <SoftwareSerial.h>

SoftwareSerial mySerial(12, 255); // rx only

char charin = 80;
char inputBuffer[BufferLength];
int value = 128;
int speed = 128;
int timer = 15;
int timermax = 15;
int inputLength = 0;
int servoval1 = 127;
int servoval2 = 127;
int tempval1, tempval2;

void setup()
{
  // motor pins must be outputs
  pinMode(PwmPinMotorA, OUTPUT);
  pinMode(PwmPinMotorB, OUTPUT);
  pinMode(DirectionPinMotorA, OUTPUT);
  pinMode(DirectionPinMotorB, OUTPUT);
  mySerial.begin(mySerialSpeed); 
#ifdef debugout
  Serial.begin(debugSerialSpeed);
#endif
}

// process a command string
void HandleCommand(char* input, int length)
{
#ifdef debugout
  Serial.print(">");
  Serial.print(input);
  Serial.print("<");
  Serial.print(length);
  Serial.println("|");
#endif
  if (length < 1) { // not a valid command
    return;
  }
  // calculate number following command (d10~d255)
  if (length > 1) {
    value = atoi(&input[1]);
    if (value > 255)
      value = 255;
    if (value < 0)
      value = 0;
    switch(input[0])
    {
    case 'd':
    case 'D':
      if (value > 127)
        value = 127;
      speed = value*2; 
      break;
    case '/':
      timermax = value; 
      break;
    case 'c':
    case 'C':
      #ifdef ServoFlip1
      servoval1 = 256 - value; 
      #else
      servoval1 = value; 
      #endif
      break;
    case 'v':
    case 'V':
      #ifdef ServoFlip2
      servoval2 = 256 - value; 
      #else
      servoval2 = value; 
      #endif
      break;
    default:
      break;
    }
  }

  timer = timermax;

  int* command = (int*)input;
  // check commands
  // note that the two bytes are swapped, ie 'RA' means command AR



  switch(*command) {


  case '2':
  case '2j':
  case '2J':
    analogWrite(PwmPinMotorB, speed);
    digitalWrite(DirectionPinMotorB, LOW);
    analogWrite(PwmPinMotorA, speed);
    digitalWrite(DirectionPinMotorA, HIGH);
    break;

  case '8':
  case '8j':
  case '8J':
    analogWrite(PwmPinMotorB, speed);
    digitalWrite(DirectionPinMotorB, HIGH);
    analogWrite(PwmPinMotorA, speed);
    digitalWrite(DirectionPinMotorA, LOW);
    break;

  case '6':
  case '6j':
  case '6J':
    analogWrite(PwmPinMotorB, speed);
    digitalWrite(DirectionPinMotorB, HIGH);
    analogWrite(PwmPinMotorA, speed);
    digitalWrite(DirectionPinMotorA, HIGH);
    break;

  case '4':
  case '4j':
  case '4J':
    analogWrite(PwmPinMotorB, speed);
    digitalWrite(DirectionPinMotorB, LOW);
    analogWrite(PwmPinMotorA, speed);
    digitalWrite(DirectionPinMotorA, LOW);
    break;

  case '9':
  case '9j':
  case '9J':
    analogWrite(PwmPinMotorB, speed);
    digitalWrite(DirectionPinMotorB, HIGH);
    break;

  case '1':
  case '1j':
  case '1J':
    analogWrite(PwmPinMotorB, speed);
    digitalWrite(DirectionPinMotorB, LOW);
    break;

  case '3':
  case '3j':
  case '3J':
    analogWrite(PwmPinMotorA, speed);
    digitalWrite(DirectionPinMotorA, HIGH);
    break;

  case '7':
  case '7j':
  case '7J':
    analogWrite(PwmPinMotorA, speed);
    digitalWrite(DirectionPinMotorA, LOW);
    break;

  default: // stop, just to be safe
    analogWrite(PwmPinMotorA, 0);
    digitalWrite(DirectionPinMotorA, LOW);
    analogWrite(PwmPinMotorB, 0);
    digitalWrite(DirectionPinMotorB, LOW);
    break;

  }  
} 

void loop()
{ 
  // get a command string form the mySerial port
  inputLength = 0;
  do {
    while (!mySerial.available()){
      // note: arduino cannot handle fullduplex on myserial so no output here!

      // do servos here
      tempval1 = (servoval1*ServoTimingStep) + ServoTimingFloor;
      tempval2 = (servoval2*ServoTimingStep) + ServoTimingFloor;
      if (servoval1 > 0)
        digitalWrite(ServoPin1,HIGH);
      delayMicroseconds(tempval1);
      if (servoval1 < 255)
        digitalWrite(ServoPin1,LOW);
      if (servoval2 > 0)
        digitalWrite(ServoPin2,HIGH);
      delayMicroseconds(tempval2);
      if (servoval2 < 255)
        digitalWrite(ServoPin2,LOW);
      delayMicroseconds(5000 - tempval1 - tempval2);
      delay(15); // reduce/remove if we're doing more things here

      // decrease the timer
      if (--timer < 0)
      { 
        timer=0;
        analogWrite(PwmPinMotorA, 0);
        analogWrite(PwmPinMotorB, 0);
      }
    }; 

    // wait for input 
    {
      charin = mySerial.read(); // read it in
#ifdef debugout
        Serial.print(charin);
        tempval1 = charin;
        Serial.println(tempval1);
#endif

      if ((charin > 46 && charin < 58) || (charin=='d') || (charin=='j') || (charin=='c') || (charin=='v'))
      {
        inputBuffer[inputLength]=charin;
        inputLength++;

#ifdef serialout
        mySerial.print("$PD,11,");
        mySerial.print(timer);
        mySerial.print(",");
        mySerial.print(value);
        mySerial.println("*");
#endif
      }

    }
  } 
  while (charin>46 && charin<119 && charin != LineEnd1 && charin != LineEnd2 && inputLength < BufferLength);
  inputBuffer[inputLength] = 0; //  add null terminator
  HandleCommand(inputBuffer, inputLength);
}
  int* command = (int*)input;
  // check commands
  // note that the two bytes are swapped, ie 'RA' means command AR



  switch(*command) {

You still haven't explained why you are doing this.

  case '2j':
  case '2J':

These are not values that you can possibly read from the serial port, so they are STILL wrong.