2
#include <Servo.h> 

Servo myservo;  // create servo object to control a servo 


int pos = 90;
String kontrolstr = "";
char kontrol;

void setup() 
{ 
  Serial.begin(9600);
  myservo.attach(9);// attaches the servo on pin 9 to the servo object 
} 

void loop()
{
  if(Serial.available())
    {
      kontrol=Serial.read(); // it reads from python voice recognition
      kontrolstr.concat(kontrol); 
    }
     if(kontrolstr== "right")
       {pos += 30;
       kontrol = '0';
       kontrolstr = "";
       }
     else if(kontrolstr== "left")
       {pos -= 30;
       kontrol= '0';
       kontrolstr = ""; 
     }

     myservo.write(pos);
     delay(100);
}

It works with voice_command.py (which I wrote) on linux terminal. When code is like this, right after uploading this code to arduino, it works well until voice recognition understand a different word from "right" or "left". When voice command send to arduino another string different from "right" or "left", program still works without any error but after this point it starts not to respond "right" or "left" command anymore. To solve this I did this change. I put an 'else':

#include <Servo.h> 

Servo myservo;  // create servo object to control a servo 


int pos = 90;
String kontrolstr = "";
char kontrol;

void setup() 
{ 
  Serial.begin(9600);
  myservo.attach(9);// attaches the servo on pin 9 to the servo object 
} 

void loop()
{
  if(Serial.available())
    {
      kontrol=Serial.read();
      kontrolstr.concat(kontrol);
    }
     if(kontrolstr== "right")
       {pos += 30;
       kontrol = '0';
       kontrolstr = "";
       }
     else if(kontrolstr== "left")
       {pos -= 30;
       kontrol= '0';
       kontrolstr = ""; 
     }
     else {              // I write this to make it work..
       kontrol = '0';  
       kontrolstr = "";
     }

     myservo.write(pos);
     delay(100);
}

However, now it is not responding "right" and "left" command too. How can I solve this problem?

Bahadır
  • 454
  • 1
  • 4
  • 8
  • 2
    Presumably the Serial.available() block is aggregating data as it comes in? So if in one iteration of the loop you get `rig`, you'll hit the "else" block and reset the string before the `ht` comes in, right? – Paul Mar 27 '16 at 01:01
  • Thanks for answer, but I could not catch what you mean clearly. Especially 'rig' and 'ht' parts. I did not understand what I should do to solve this problem. Can you open it up a little bit for me to understand it well. I am new in arduino by the way :) – Bahadır Mar 27 '16 at 23:43

1 Answers1

1

The Problem

The problem you are having is that your Serial.available() block is only reading one byte from the Serial buffer in each iteration of the loop. As a consequence, when your servo sends the word "right", the Serial buffer is "right". The first iteration through loop() gives "r" as the value for kontrolstr.

Without the else block, on the second loop, kontrolstr is set to ri, then rig, then righ, etc, and is only reset when left or right are found. This is also what causes the problem of left and right not being reached if another word has been recognized - kontrolstr would have been set to , e.g. "horse", this is not recognized, so then when it sends "right", you get "horseright", etc.

With the else block, on the first loop, kontrolstr is "r", so it hits the else block, and resets the string. On the second loop, kontrolstr is "i", it hits the else block and resets the string, etc, never reaching the relevant control block.

Possible solutions

The start of the solution is to read the entire Serial buffer before processing it, so replace the block starting with if(Serial.available() to:

while(Serial.available())
  {
    kontrol = Serial.read();
    kontrolstr.concat(kontrol);
  }

This will read the entire buffer in the first loop, so as long as all the data has been sent between iterations of the loop, your problem will be solved. However, it takes a non-zero amount of time to send data over a Serial port, so it's possible that your loop() iteration triggers in the middle of a send, in which case the Serial buffer might be something like "rig", which won't match "right" or "left", will be reset, then in the next loop you'll get "ht", and again it will be reset - the trigger will be missed.

If possible, I think the best solution would be to have your servo send the control words with a delimiter between them, e.g. \n. If your servo sends "right\nanother word\nleft\n", then you can wait for entire words to come in before processing them. You can do this by changing your loop() to:

void loop()
{
  kontrolstr = "";    // Reset on each iteration of the loop
  while(Serial.available())
  {
    kontrol = Serial.read();
    // If we reach the delimiter, stop reading from the Serial buffer
    if (control == '\n') {
      break;
    }
    kontrolstr.concat(kontrol);
  }
  if(kontrolstr== "right") {
    pos += 30;
  } else if(kontrolstr== "left") {
    pos -= 30; 
  }

  myservo.write(pos);
  delay(100);
}

Of course, this assumes that you're OK with allowing extra words to accumulate in the Serial buffer (seems fine since the buffer wasn't filling up even when you were reading only 1 character every 100ms). However, if it does happen that the Serial buffer is overflowing, then you can create a second string bufferstring and always append whatever is in the Serial buffer to that string, then on each iteration of the loop, pull out the oldest command, giving:

#include <Servo.h> 

Servo myservo;  // create servo object to control a servo 

int pos = 90;
String kontrolstr = "";
String bufferstring = "";
char kontrol;

void setup() 
{ 
  Serial.begin(9600);
  myservo.attach(9);// attaches the servo on pin 9 to the servo object 
} 

void loop()
{
  // Read whatever's in the Serial port into the buffer string
  while(Serial.available())
  {
    kontrol = Serial.read();
    // If we reach the delimiter, stop reading from the Serial buffer
    bufferstring.concat(kontrol);
  }

  // Split the string by the delimiter
  int delimiter_loc = bufferstring.indexOf('\n');
  if (delimiter_loc != -1) {
    // Get the first delimiter_loc characters (doesn't include the delimiter)
    kontrolstr = bufferstring.substring(0, delimiter_loc);

    // Remove all the characters up to and including the delimiter_loc
    bufferstring.remove(0, delimiter_loc + 1);
  }

  if(kontrolstr== "right") {
    pos += 30;
  } else if(kontrolstr== "left") {
    pos -= 30;
  }

  // Reset on each iteration of the loop
  kontrolstr = "";

  myservo.write(pos);
  delay(100);
}
Paul
  • 10,381
  • 13
  • 48
  • 86
  • This is far much better answer than I expected to get. Thanks a lot for such a clear and long answer! – Bahadır Mar 28 '16 at 04:20