How to make an internal interruption by serial

Hi, i'm trying to make a simple car using two servos. When an specific command is readed, the motors make a movement for a 5 seconds. But I want to know how I can make an interruption when a new command is readed while a movement is making before the 5 seconds pass.

This is the code that I have, can you help me?:

#include <stdlib.h>
#include <Servo.h>

Servo left; 
Servo right; 
int speed = 100;


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

void loop()
{
   refreshData();
  
}

void refreshData()
{ 
  Stop();
  if (Serial.available() > 0) {
  char *data = "";
  *data = Serial.read();
  int command = atol (data);
  Serial.println(command);
  processCommand(command);
  }
}


void processCommand(int command)
{ 
  
  if (command == 1) {  
    goF();
    delay(5000);
    Stop();
  }
  else if (command == 2) {
    goB();
    delay(5000);
    Stop();
  }
  else if (command == 3) {
    goR();
    delay(5000);
    Stop();
  }
  else if (command == 4) {
    goL();
    delay(5000);
    Stop();
  }
  else {
    goF();
    delay(200);
    goB();
    delay(200);
   
  }
}

//Planteamiento de funciones de movimiento */

void setupServo()
{
  left.attach(10); 
  right.attach(9);  
}

void setSpeed(int newVel)
{
  if(newVel >= 100) {
  newVel = 100;
  }
  if(newVel <= 0) {
  newVel = 0;
  }      
  speed = newVel * 0.95;                   
}

void goF()
{
 left.write(95 + speed);
 right.write(95 - speed);
}

void goB()
{
 left.write(95 - speed);
  right.write(95 + speed);
}
  
void goR()
{
 left.write(95 + speed);
  right.write(95 + speed);
}

void goL()
{
 left.write(95 - speed);
 right.write(95 - speed);
}

void Stop()
{
 left.write(95);
 right.write(95);
}

The short answer is that you can NOT get an interrupt from the Serial (AsFarAsIKnow) as it already uses it internally. The Serial buffers all incomming characters in a buffer, which you retrieve one at a time with the .read() function. That is why .available can return a number, ie how many characters are waiting in that buffer.

Secondly, the *data = "" is not allocating a "buffer" for you, it points to some arbitary location where there is single nul-byte (the string terminator). So I suspect you overwrite random bytes when you put a char to it, but as it only is one byte, it seems luckly work out. You have to allocate a buffer with char data[5] or something like that. Alternativly look at the Strings library/datatype.

So, we come to the "old" problem (you're not the first to ask :wink: ) about doing something else while delay() is blocking execution. The answer is NOT TO USE DELAY(). There is the infamaous BlinkLEDWithoutDelay example in the tutorials, but it somehow explains it badly ( as so many ask ). Still, required reading.

So you need to change your main loop so you call a routine to check&process for input from Serial, then it always calls movemotor(). This routine has a variable that was set to millis()+5000 at the start and starts the motors and if the current millis() is greater that value you do stop the motors. (We'll ignore the wrap around that will occur after 49 days, and DO make sure the timer variables use unsigned long and not int)

As you can see this means your loop will constantly check for Serial input, and constantly check if the motors should stop turning, and they will stop after 5 seconds and we have not used any delay(). Ta-Da!

Your code is nicely structured and well laid out, so I am sure you can do this with above hint(s).

Msquare, thanks for your excellent answer and your suggestions. Now I can understand better the how works the serial communication... I understood what you said about use millis(), but I think that it can't solve my problem; what I really need is to "brake" the motors, while both are moving until x time, but x is not reached yet. ie in my proyect the time per movement is 5 seconds, the motors start to move, the robot is going to hit an obstacle and the 5 seconds has not pass yet, so I will write a command with the intention that the robot can stops before crash.

...Yes I lied, I'm not making a simple car and doing a robot. I'm finish the Junior year in my high school, so I decided to make a great final proyect. I started a week ago and my proyect still under construction, but my idea is that the robot can recognize voice commands and in addition to that, it can move in an spefic direction, speak or show expressions in a led matrix.

If you and anybody want to see the code what I have. This is it (sorry, I'm a spanish native so almost all the code is commented and structured in spanish):

#include <stdlib.h>
#include <Servo.h>
//declaracion de variables

Servo izquierdo; 
Servo derecho; 
int speed = 95; // velocidad inicial servos
int speedMatrix = 5; // velocidad matriz, numero de veces que se repite cada fotograma
int rowA[] = {9,8,7,6,5,4,3,2}; // pins filas matriz led        
long tiempoanterior = 0; // tiempo transcurrido antes del movimiento
long intervalo = 5000;
int colA[] = {17,16,15,14,13,12};  // pins columnas matriz
byte data[] = {0,0,0,0,0,0,0,0};  
//--------------------------------------------------

//Inicio del programa de recepcion de comandos
//------------------------------------------------------------------------------------------------------------

void setup()
{
  iniciarServo();
  Serial.begin(9600);
  for(int i = 0; i <8; i++){ //establecer todos los pines de la matriz como OUTPUT
    pinMode(rowA[i], OUTPUT);
    pinMode(colA[i], OUTPUT);
  }
}

void loop()
{
   
   bocacerrada();
   refrescarDatos();
 
}

void refrescarDatos()
{ 
  
  Parar();
if (Serial.available() > 0) {
  char *datos = "";
  *datos = Serial.read();
  int comando = atol (datos);
  Serial.println(comando);
  procesarcomando(comando);
  }
}
  
void procesarcomando(int comando) {
    
  if (comando == 1) {  
    irAdelante();
    delay(5000);
    Parar();
    tiempoanterior = millis();
  }
  else if (comando == 2) {
    irAtras();
    delay(5000);
    Parar();
    tiempoanterior = millis();
  }
  else if (comando == 3) {
    irDerecha();
    delay(5000);
    Parar();
    tiempoanterior = millis();
  }
  else if (comando == 4) {
    irIzquierda();
    delay(5000);
    Parar();
    tiempoanterior = millis();
  }
  else if (comando == 5) {
    long boca = 1300;
     feliz(boca);
    tiempoanterior = millis();
  }
  else if (comando == 6) {
    long boca = 1300;
     triste(boca);
    tiempoanterior = millis();
  }
  else if (comando == 7) {
    long boca = 1300;
     enamorado(boca);
    tiempoanterior = millis();
  }
  else if (comando == 8) {
    long boca = 300;
     bocaabierta(boca);
    tiempoanterior = millis();
  }
  else if (comando == 9) {
    irDerecha();
    delay(2000);
    irIzquierda();
    delay(1000);
    irDerecha();
    delay(1000);
    irAdelante();
    delay(500);
    irAtras();
    delay(500);
    irAdelante();
    delay(500);
    irAtras();
    delay(300);
    irAdelante();
    delay(100);
    irAtras();
    delay(200);
    irIzquierda();
    delay(7000);
    irDerecha();
    delay(2000);
  }
  else {
    irAdelante();
    delay(200);
    irAtras();
    delay(200);
  }
 }

//Planteamiento de funciones de movimiento

void iniciarServo()
{
  izquierdo.attach(11); 
  derecho.attach(10);  
}

void setSpeed(int nuevaVel)
{
  if(nuevaVel >= 100) {
  nuevaVel = 100;
  }
  if(nuevaVel <= 0) {
  nuevaVel = 0;
  }      
  speed = nuevaVel * 0.95;                   
}

void irAdelante()
{
 izquierdo.write(95 + speed);
 derecho.write(95 - speed);
}

void irAtras()
{
 izquierdo.write(95 - speed);
 derecho.write(95 + speed);
}
  
void irDerecha()
{
 izquierdo.write(95 + speed);
 derecho.write(95 + speed);
}

void irIzquierda()
{
 izquierdo.write(95 - speed);
 derecho.write(95 - speed);
}

void Parar()
{
 izquierdo.write(95);
 derecho.write(95);
}

void bocacerrada() {
    data[0] = B11000011; //figura que aparece en la matriz
    data[1] = B11000011;
    data[2] = B00000000;
    data[3] = B11111111;
    data[4] = B11111111;
    data[5] = B00000000;
    showSprite(speedMatrix);
}

void bocaabierta(long boca){
  tiempoanterior = millis();
   while (millis() - tiempoanterior < boca) {
    data[0] = B11000011; //figura que aparece en la matriz
    data[1] = B11000011;
    data[2] = B00000000;
    data[3] = B11111111;
    data[4] = B10000001;
    data[5] = B11111111;
    showSprite(speedMatrix);
    showSprite(speedMatrix);
    }
}
void feliz(long boca){
  tiempoanterior = millis();
  
   while (millis() - tiempoanterior < boca) {
    data[0] = B11000011; //figura que aparece en la matriz
    data[1] = B11000011;
    data[2] = B00000000;
    data[3] = B11111111;
    data[4] = B10000001;
    data[5] = B01111110;
    showSprite(speedMatrix);
    showSprite(speedMatrix);
    }
}
void triste(long boca){
  tiempoanterior = millis();
   while (millis() - tiempoanterior < boca) {
    data[0] = B11000011; //figura que aparece en la matriz
    data[1] = B11000011;
    data[2] = B00000000;
    data[3] = B01111110;
    data[4] = B10000001;
    data[5] = B11111111;
    showSprite(speedMatrix);
    showSprite(speedMatrix);
    }
}
void enamorado(long boca){
  tiempoanterior = millis();
   while (millis() - tiempoanterior < boca) {
    data[0] = B01100011; //figura que aparece en la matriz
    data[1] = B01010101;
    data[2] = B01001001;
    data[3] = B00100010;
    data[4] = B00010100;
    data[5] = B00001000;
    showSprite(speedMatrix);
    showSprite(speedMatrix);
    }
}  

// Funcion de la matriz

//An array to store power values to act as bit masks
const int powers[] = {1,2,4,8,16,32,64,128};

//Runs a pattern where each LED is lit one after another

void showSprite(int speed2){
 for(int iii = 0; iii < speed2; iii++){                 //show the current frame speed2 times
  for(int column = 0; column < 8; column++){            //iterate through each column
   for(int i = 0; i < 8; i++){                          
       digitalWrite(rowA[i], LOW);                      //turn off all row pins  
   }
   for(int i = 0; i < 8; i++){ //Set only the one pin
     if(i == column){     digitalWrite(colA[i], LOW);}  //turns the current row on
     else{                digitalWrite(colA[i], HIGH); }//turns the rest of the rows off
   }

   for(int row = 0; row < 8; row++){                    //iterate through each pixel in the current column
    int bit = (data[column] >> row) & 1;
    if(bit == 1){ 
       digitalWrite(rowA[row], HIGH);                   //if the bit in the data array is set turn the LED on
    }

   }                   //leave the column on for pauseDelay microseconds (too high a delay causes flicker)
  } 
 }
}

Click on the link If you want to see a little preview of the Robot (remember that I speak spanish and that I'm still working in my proyect)

*Please give me opinions and suggestions of all my proyect
*In a few weeks I will leave the breadboard and I will post my progress :).

char *datos = "";
  *datos = Serial.read();

Didn't you read the comment about writing over random data?

but my idea is that the robot can recognize voice commands

That's going to need something more powerful than an Arduino to help with that - claps, maybe, spoken commands, very unlikely.

You really need to work on getting rid of all those "delay"s.

AWOL thanks for your suggestions. I don't have changed the *data part yet because I don't have a lot of time, but i'm working on it, I just wanted to share my entire code. This is a proyect to be delivery in october; and in addition to that, I have a lot of future ideas to work on it, I am newbie and I started only a few days ago.

*I know that my solution of "voice recognition" is very poor but I decided that because I can't expend a lot of money, so I have to think in very easy solutions. How ever a future idea is to implement the Adafruit Wave Shield with the intention of improve it.

Hi,

This is in the "Project Guidance" forum, and my comment in that context is that I think that you have an ambitious but possible project, although voice recognition is a very tall order (I dont know how much intelligence the WaveShield you mention has, if it can do the wave-match voice-recognition trick). And you seem to have most pieces. Nice video. Is it showing anything that does not work as intended?

As far as the programming goes, the last example of your working code still contains the two hurdles you need to get over - avoid using delay() and do not store things with *char unless you have allocated a buffer (or use the String library). I have not studied your code in detail. (You could alse change the if ( command== ..) to a switch/case construct.

Feel free to start a new topic under Programming with a specific problem. (The original question "interrupt for Serial" should have been there)

Thanks for your constructive feedback. I'm trying to use char data[5] but it does not works for me, however I'll keep working in all my project, specificly in avoid delays.

Finally thanks for suggest the use of switch/case I'll read about it :).