Unsing Serial and Intterupts

Hi everyone, I’m very desperate because I’ve been working in this code for this Week and I’m no been able to make it works. In simple words, is controlling 4 motors of a vehicle and each motor has a quadrature encoder, actually is this https://www.sparkfun.com/products/10336

and I’m using mecum wheels for make it able to move right and left.
My programs needs to read a command to know the direction to go and a distance, to move according that distance.

And I’ve done the function of each requirement.
The problem is that, when I try to give it the values of each function trough the Serial Monitor, it doesn’t work. Only the function to set the direction, and the one for the distance doesn’t work.

Excuse me for my english… :frowning:
And thank u so much for the help that anyone could give me.

Here is the code

// Pines de interrupciones Mega
//  int.0  int.1  int.2  int.3  int.4  int.5
//    2      3      21    20      19     18
//                  A1    A2      B1     B2  
long previousMillis = 0; //Variables para la velocidad
long interval = 1000;

unsigned long previousTime = 0; //Variables para avanzar la distancia en el tiempo
unsigned long time = 0;

volatile int contA1 = 0; //Variables para medir
volatile int contA2 = 0; //los pulsos de los encoders
volatile int contB1 = 0; //en los motores del coche
volatile int contB2 = 0; //

int motorA1S = 7; //Variables de los motores
int motorA2S = 4; //donde estan los PWM
int motorB1S = 6;
int motorB2S = 5;

int motorA1D = 28; //Variables de los motores
int motorA2D = 22; //donde estan la direccion
int motorB1D = 26;
int motorB2D = 24;

int trailMotorA1=0; //Distancia recorrida de cada motor o velocidad
int trailMotorA2=0;
int trailMotorB1=0;
int trailMotorB2=0;

//Velocidad deseada 40 cm/s
const int pwmPrueba = 127;
const int desireSpeed = 40;
boolean isWheelMoving = false;
boolean isDesireSpeed = false;
boolean isDistance = false;

//Los PWM que almacenan la PWM que necesita para ir a la velocidad deseada
int motorA1PWM = 0;
int motorA2PWM = 0;
int motorB1PWM = 0;
int motorB2PWM = 0;

//Variables para la comunicacion
const int MAXCHAR = 3; 
int fieldIndex = 0;   //Bandera para hacer los corrimientos de posicion
char buffer[MAXCHAR]; //Buffer para almacenar la distancia
char command;     //Commando para decir a que direccion ir
int distance = 0; //Distancia para saber cuanto tiene que avanzar

boolean isTime = false;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(2, motorA1, RISING);
  attachInterrupt(3, motorA2, RISING);
  attachInterrupt(4, motorB1, RISING);
  attachInterrupt(5, motorB2, RISING);
  
  pinMode(motorA1D, OUTPUT);
  pinMode(motorA2D, OUTPUT);
  pinMode(motorB1D, OUTPUT);
  pinMode(motorB2D, OUTPUT);
}

void loop()
{
  processingData();
//  directionToGo(command);
//  reachDistance(distance);
}

void processingData()
{ 
  if(Serial.available())
  {
    char ch = Serial.read();
    
    if((ch == 'w') || (ch == 's') || (ch == 'a') || (ch == 'd'))
    {
      command = ch;
//      Serial.print("Command: ");Serial.print(command);
      directionToGo(command);
    }
    
    else if((ch >= '0') && (ch  <= '9'))
    {
      buffer[fieldIndex++] = ch;
    }
    
    else if((ch == 'f'))
    {
      distance = atoi(buffer);
//      time = (distance*1000)/(desireSpeed);
//      Serial.print(" Distance: ");Serial.print(distance);
////      Serial.print(" Time: ");Serial.println(time);
      reachDistance(distance);
      
      for(int i=0;i<MAXCHAR;i++)
      {
        buffer[i] = 0;
      }
      fieldIndex = 0; 
    }
    
    else
    {
      distance = 0;
      command = 0;
    }
    
  }
}

void directionToGo(char direction) //Funcion para saber la direccion que tiene que moverse
{
  switch(direction)
  {
    case 'w': //Adelante
//      Serial.println("Adelante");
      reachDistance(distance);
      digitalWrite(motorA1D, LOW); //28
      digitalWrite(motorA2D, HIGH); //22
      digitalWrite(motorB1D, LOW); //26
      digitalWrite(motorB2D, HIGH); //24
      break;
    
    case 's': //Atras
//      Serial.println("Atras");
      digitalWrite(motorA1D, HIGH);
      digitalWrite(motorA2D, LOW);
      digitalWrite(motorB1D, HIGH);
      digitalWrite(motorB2D, LOW);
      break;
    
    case 'a': //Izquierda
//      Serial.println("Izquierda");
      digitalWrite(motorA1D, LOW);
      digitalWrite(motorA2D, HIGH);
      digitalWrite(motorB1D, HIGH);
      digitalWrite(motorB2D, LOW);
      break;
    
    case 'd': //Derecha
//      Serial.println("Derecha");
      digitalWrite(motorA1D, HIGH);
      digitalWrite(motorA2D, LOW);
      digitalWrite(motorB1D, LOW);
      digitalWrite(motorB2D, HIGH);
      break;
    
    default: //Alto
//      Serial.println("Detente");
      analogWrite(motorA1S,0);
      analogWrite(motorA2S,0);
      analogWrite(motorB1S,0);
      analogWrite(motorB2S,0);
      break;
  }
}

void getDesireSpeed(int speedReference)
{
//  Serial.println("Entramos a la funcion");
  if(!isDistance)
  {
   if((!isWheelMoving) && (!isDesireSpeed)) //Si no se mueve movemos las llantas
    {
//      Serial.println("No hay movimiento, movemos las llantas");
      motorA1PWM = pwmPrueba;
      motorA2PWM = pwmPrueba;
      motorB1PWM = pwmPrueba;
      motorB2PWM = pwmPrueba;
      
      analogWrite(motorA1S, motorA1PWM); //Con este a 90 PWM la mayoria va igual
      analogWrite(motorA2S, motorA2PWM);
      analogWrite(motorB1S, motorB1PWM);
      analogWrite(motorB2S, motorB2PWM);
      
      isWheelMoving = true; //Decimos que ya se esta moviendo
      isDesireSpeed = false;
    }
    
    if(isDesireSpeed) //Si ya conseguimos la velocidad deseada
    {
      byte newMotorA1PWM=0;
      byte newMotorA2PWM=0;
      byte newMotorB1PWM=0;
      byte newMotorB2PWM=0;
      
      newMotorA1PWM = motorA1PWM; //Hacemos que los motores vayan a los nuevos PWM
      newMotorA2PWM = motorA2PWM; //que se crean en base a la velocidad
      newMotorB1PWM = motorB1PWM;
      newMotorB2PWM = motorB2PWM;
      
      analogWrite(motorA1S, newMotorA1PWM); //Con este a 90 PWM la mayoria va igual
      analogWrite(motorA2S, newMotorA2PWM);
      analogWrite(motorB1S, newMotorB1PWM);
      analogWrite(motorB2S, newMotorB2PWM);
    }
    
    if((isWheelMoving) && (!isDesireSpeed)) //Si se esta moviendo, pero aun no van a la = velocidad
    { //Calculamos la velocidad en un segundo
      unsigned long currentMillis = millis(); 
      if(currentMillis - previousMillis > interval)
      {
        previousMillis = currentMillis;
        
        trailMotorA1 = (contA1*17)/180; //17/180
        trailMotorA2 = (contA2*17)/180; //17/180
        trailMotorB1 = (contB1*17)/180; //17/180
        trailMotorB2 = (contB2*17)/180; //17/180
        
        contA1 = 0;
        contA2 = 0;
        contB1 = 0;
        contB2 = 0;
      } //Todo este bloque se hace en un segundo o eso deberia...
      
      // Ajuste de la velocidad
  
      if(trailMotorA1 > speedReference)
      {
        motorA1PWM--;
      }
      
      else
      {
        motorA1PWM++;
      }
      
      if(trailMotorA2 > speedReference)
      {
        motorA2PWM--;
      }
      
      else
      {
        motorA2PWM++;
      }
      
      if(trailMotorB1 > speedReference)
      {
        motorB1PWM--;
      }
      
      else
      {
        motorB1PWM++;
      }
      
      if(trailMotorB2 > speedReference)
      {
        motorB2PWM++;
      }
      
      else
      {
        motorB2PWM--;
      }
      
      if((trailMotorA1 = speedReference) &&
         (trailMotorA2 = speedReference) &&
         (trailMotorB1 = speedReference) &&
         (trailMotorB2 = speedReference))
         {
           isDesireSpeed = true;
         }
      
    } 
  }
  
  else
  {
    analogWrite(motorA1S, 0);//motorA1PWM); //Con este a 90 PWM la mayoria va igual
    analogWrite(motorA2S, 0);//motorA2PWM);
    analogWrite(motorB1S, 0);//motorB1PWM);
    analogWrite(motorB2S, 0);//motorB2PWM);
  }

}

void reachDistance(int distanceMeasured)//, unsigned long time) //Recibimos la distancia deseada
{ 
//  Serial.print("Received distance: ");Serial.println(distanceMeasured);
  unsigned long currentTime = millis(); 
  time = (distanceMeasured*1000)/(desireSpeed); //Calculmos el tiempo que nos llevaria alcanzar la velocidad
  
  if(currentTime - previousTime > time) //Pasan el tiempo se ejecuta la accion 
  { 
    previousTime = currentTime;
    
    motorA1PWM = 0;
    motorA2PWM = 0;
    motorB1PWM = 0;
    motorB2PWM = 0;
    
    analogWrite(motorA1S, motorA1PWM); //Con este a 90 PWM la mayoria va igual
    analogWrite(motorA2S, motorA2PWM);
    analogWrite(motorB1S, motorB1PWM);
    analogWrite(motorB2S, motorB2PWM);
    
    isWheelMoving = false;
    isDistance = true;
    
//    isTime = false;
    
  }
  
  else// if(!isTime)
  {
    getDesireSpeed(desireSpeed);
  }
}

void motorA1()
{
  contA1++;
}

void motorA2()
{
  contA2++;
}

void motorB1()
{
  contB1++;
}

void motorB2()
{
  contB2++;
}

See:

Look at this, >0 do you have it?

Yes, I’ve tried with both, Serial.available() and Serial.available() > 0

The problem is that the function that uses the serial communication to get the values of distance and the direction, works. But when I tried to call the other functions using that values, it doesn’t works… Instead of writing the values manually, for example directionToGo(‘w’) and reachDistance(30). ← This works… but with the values of the function where I get those values through serial, doesn’t works.

I really haven't look closely at all your sketch.

Have you tried to insert some debug code to see if variables are what you are expecting?
example:

Serial.print ("I just recieved the character: ");
Serial.println (ch);

Or Serial.print other variables to prove things are what they are supposed to be.

const int MAXCHAR = 3; 
int fieldIndex = 0;   //Bandera para hacer los corrimientos de posicion
char buffer[MAXCHAR]; //Buffer para almacenar la distancia

What do you type in the serial monitor (what number)?

Also what do you have set as line-endings? (newline? or what?)

I suspect MAXCHAR is too small.

Yes, and thank u for check it.

My function in Serial Works, but I don't know why, after using serial, the variables that I get with the function doesn't works on the another functions.

I send an 'f' to finish the "package".

And the message that I suppose to get, for example
w123f

It means the 'w' is the direction and the 123 the distance to move.

How is this supposed to work? (a question, not a criticism)

 else if((ch >= '0') && (ch  <= '9'))
    {
      buffer[fieldIndex++] = ch;
    }
    
    else if((ch == 'f'))
    {
      distance = atoi(buffer);

I think atoi() expects a null terminated string and I don’t see any 0 being added.

As well as which I can’t figure what the filedIndex++ does? I understand that it increments the index - but why?

…R

To move to the next space of the buffer, and this part of the code works, because actually when I try to print the values of "command" and "distance" it print them. But the problem is what when I want to use these values on the other function the program, just don't do it.

const int MAXCHAR = 3; 
int fieldIndex = 0;   //Bandera para hacer los corrimientos de posicion
char buffer[MAXCHAR]; //Buffer para almacenar la distancia

OK you are getting a 3-digit number like 123. You also need room for the null terminator (so MAXCHAR needs to be 4 at least, and if you type 1234 it would need to be 5 and so on. Then you should put that there:

      buffer[fieldIndex++] = ch;
      buffer[fieldIndex] = 0;  // null terminator

JaviHer:
To move to the next space of the buffer, and this part of the code works, because actually when I try to print the values of "command" and "distance" it print them. But the problem is what when I want to use these values on the other function the program, just don't do it.

Prove it. Display the value after you get the "f".

      distance = atoi(buffer);
      //      time = (distance*1000)/(desireSpeed);
      //      Serial.print(" Distance: ");Serial.print(distance);
      ////      Serial.print(" Time: ");Serial.println(time);

      Serial.print ("distance is now ");
      Serial.println (distance);

      reachDistance(distance);

Then display it inside reachDistance. Post your displays here.

This was what I got, and actually I wrote a Serial.print in my function reachDistance, and it looks like it really get it, but the function doesn’t do what it should.

i send w30f and this was the result.

distance is now: 30
Received distance: 30

Actually the function that receive the direction “w” “s” “d” or “a” works, because I’ve check it with my multimeter and every time that I change the command the voltage on the pins change. The problem is the other function.

And here is the code.

oid processingData()
{ 
  if(Serial.available() > 0)
  {
    char ch = Serial.read();
    
    if((ch == 'w') || (ch == 's') || (ch == 'a') || (ch == 'd'))
    {
      command = ch;
//      Serial.print("Command: ");Serial.print(command);
      directionToGo(command);
    }
    
    else if((ch >= '0') && (ch  <= '9'))
    {
      buffer[fieldIndex++] = ch;
    }
    
    else if((ch == 'f'))
    {
      distance = atoi(buffer);
      Serial.print("distance is now: ");Serial.println(distance);
      reachDistance(distance);
      for(int i=0;i<MAXCHAR;i++)
      {
        buffer[i] = 0;
      }
      fieldIndex = 0; 
    }
    
    else
    {
      distance = 0;
      command = 0;
    }
    
  }
}

And the function reachDistance

void reachDistance(int distanceMeasured)//, unsigned long time) //Recibimos la distancia deseada
{ 
  Serial.print("Received distance: ");Serial.println(distanceMeasured);
  
  unsigned long currentTime = millis(); 
  time = (distanceMeasured*1000)/(desireSpeed); //Calculmos el tiempo que nos llevaria alcanzar la velocidad
  
  if(currentTime - previousTime > time) //Pasan el tiempo se ejecuta la accion 
  { 
    previousTime = currentTime;
    
    motorA1PWM = 0;
    motorA2PWM = 0;
    motorB1PWM = 0;
    motorB2PWM = 0;
    
    analogWrite(motorA1S, motorA1PWM); //Con este a 90 PWM la mayoria va igual
    analogWrite(motorA2S, motorA2PWM);
    analogWrite(motorB1S, motorB1PWM);
    analogWrite(motorB2S, motorB2PWM);
    
    isWheelMoving = false;
    isDistance = true;
    
//    isTime = false;
    
  }
  
  else// if(!isTime)
  {
    getDesireSpeed(desireSpeed);
  }
}

I didn’t use delay, because I’m using interrupts and I read that it could have problems…
Thank u so much for the help.

I think you are having trouble accepting the errors you have in your code. EVEN if you believe the errors being pointed out to you are not causing trouble. You should correct them before you go any further.

I have never known Nick Gammon to be wrong on anything. You are getting the benefit of expertise that would cost you dearly in any other environment. Please read through his comments again and take action to remedy your mistakes. If you then still have problems we might have a chance of uncovering any further issues.

My function in Serial Works, but I don't know why, after using serial, the variables that I get with the function doesn't works on the another functions.

I think we have established that the number does in fact get passed to the function.

But the problem is what when I want to use these values on the other function the program, just don't do it.

Hmm.

  time = (distanceMeasured*1000)/(desireSpeed); //Calculmos el tiempo que nos llevaria alcanzar la velocidad

Now display the value of time. This is called debugging. If things don't work display the values you are working with. They may not be what you expect. And then copy and paste your results here.

I have never known Nick Gammon to be wrong on anything.

Thanks, Ken, but I could tell you some stories ... :wink:

Sorry if I'd expressed wrong, but I'm not telling that Nick is wrong, I really appreciate the help.
And I will do the Serial.print, and before going further... to resume

My function of "proccesingData()" it looks that works, because when I print the values on the monitor serial it show them.

And when I call the function "directionToGo()" it works too, because I've tested with my multimeter and it really makes the changes...

Now in the function "reachDistance()" it looks to be a problem... even it really get the distance because at the moment of print it on the monitor serial, show it. But now I'm going to print the next steps as Nick said and see what happened.