#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);
}
它适用于 linux 终端上的voice_command.py(我写的(。当代码像这样时,在将此代码上传到arduino之后,它会很好地工作,直到语音识别理解与"右"或"左"不同的单词。当语音命令向arduino发送另一个不同于"右"或"左"的字符串时,程序仍然可以正常工作,但在此之后,它开始不再响应"右"或"左"命令。为了解决这个问题,我做了这个改变。我放了一个"其他":
#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);
}
但是,现在它也没有响应"右"和"左"命令。如何解决这个问题?
问题
您遇到的问题是,Serial.available()
块在循环的每次迭代中仅从串行缓冲区读取一个字节。因此,当您的伺服发送单词"right"
时,串行缓冲区是"正确的"。通过 loop()
的第一次迭代给出 "r"
作为kontrolstr
的值。
如果没有else
块,在第二个循环中,kontrolstr
设置为 ri
,然后是 rig
,然后是 righ
等,并且仅在找到left
或right
时才重置。这也是导致left
的问题,如果识别出另一个单词,则无法到达right
- kontrolstr
将被设置为 ,例如 "horse"
,这是无法识别的,所以当它发送"right"
时,你会得到"horseright"
,等等。
对于else
块,在第一个循环中,kontrolstr
"r"
,因此它命中else
块,并重置字符串。在第二个循环中,kontrolstr
"i"
,它击中else
块并重置字符串等,从未到达相关的控制块。
可能的解决方案
解决方案的开始是在处理之前读取整个Serial
缓冲区,因此将if(Serial.available()
开头的块替换为:
while(Serial.available())
{
kontrol = Serial.read();
kontrolstr.concat(kontrol);
}
这将在第一个循环中读取整个缓冲区,因此只要在循环迭代之间发送了所有数据,您的问题就会得到解决。但是,通过串行端口发送数据需要非零时间,因此您的loop()
迭代可能会在发送过程中触发,在这种情况下,串行缓冲区可能类似于 "rig"
,它不会匹配"right"
或"left"
,将被重置,然后在下一个循环中你会得到"ht"
, 它将再次重置 - 触发器将被错过。
如果可能的话,我认为最好的解决方案是让您的伺服发送控制字,并在它们之间带有分隔符,例如 n
.如果您的伺服发送"rightnanother wordnleftn"
,那么您可以在处理它们之前等待整个单词进入。为此,您可以将loop()
更改为:
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);
}
当然,这假设您可以允许在串行缓冲区中累积额外的单词(看起来很好,因为即使您每 100 毫秒仅读取 1 个字符,缓冲区也没有填满(。但是,如果确实发生了串行缓冲区溢出的情况,则可以创建第二个字符串bufferstring
并始终将串行缓冲区中的任何内容附加到该字符串,然后在循环的每次迭代中,拉出最旧的命令,给出:
#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);
}