Arduino sketch with Serial.available() passes twice - arduino

When I test Serial.available() or Serial.available() > 0 in my loop() function, it appears to return true twice each time I enter serial data. The second time, it sets the throttle value in my code to 0. Here is the code:
#include <Servo.h>
Servo rc_rotor;
int throttle = 0; // servo position indicates throttle position.
String s_throttle_set = "Throttle set to: ";
String s_throttle_read = "Reading throttle value: ";
String s_action_error = "No action known for input value: ";
void setup()
{
rc_rotor.attach(9);
Serial.begin(9600);
while(! Serial);
Serial.println("Throttle value: 0 through 255, or 999 to read current value.");
}
void loop()
{
rc_rotor.write(throttle);
delay(20);
if (Serial.available())
{
int temp_throttle = Serial.parseInt();
if (temp_throttle >= 0 && temp_throttle <= 180)
{
throttle = temp_throttle;
Serial.println(s_throttle_set + throttle);
}
else if (temp_throttle == 999)
{
Serial.println(s_throttle_read + throttle);
}
else
{
Serial.println(s_action_error + temp_throttle);
}
}
}
Please note this code is not my final masterpiece. Much of it is from publicly available examples. Anyway, the statement if (Serial.available()) succeeds twice. By that I mean, it is true when I type in a value such as 125, and a moment later it will be 'true' again when I have typed in nothing additional. I only expect one value to go through this way. The result is that my throttle is being set to the value I enter, and then almost immediately re-set to 0. Why would something like this happen?

It turns out there is no mysterious problem with the hardware or the code, as I first suspected there was. Actually, the solution is simply to select "no line ending" in the Arduino Serial Monitor's dropdown option (by default, I guess mine was set to "New Line"). Without the additional character being inserted by the Serial Monitor, everything behaves as expected.
One thing I did not expect is how the Arduino software interprets the newline. I debugged by printing the ascii values that were making it through my if-statement. First of all, the Serial Monitor sent the number I typed in, followed moments later by ascii 10, which is the line feed character. Fine, no problem. But then Serial.parseInt() chewed on that line feed for a moment (there was a slight but noticeable delay), then fed the numeral 0 to my function. It took me a little while to figure out why. Here is an explanation from the Serial part of the Arduino Language Reference:
parseInt()
Description
Looks for the next valid integer in the incoming serial stream.
parseInt() inherits from the Stream utility class.
In particular:
Initial characters that are not digits or a minus sign, are skipped;
Parsing stops when no characters have been read for a configurable
time-out value, or a non-digit is read;
If no valid digits were read
when the time-out (see Serial.setTimeout()) occurs, 0 is returned;
So Serial.available() is true after the line feed character enters the buffer, but there is no "valid digit" according to Serial.parseInt(). Understandably... we are looking at an empty buffer that finally times out. Therefore Serial.parseInt() returns 0 and the code that follows proceeds with that value.
The code in the question assumed that the only input would be integers coming over the serial connection, which is actually a pretty fragile assumption. If you need to use Serial.parseInt in a situation where empty buffers (null), line feeds or other unexpected characters might come through, it should just be a matter of filtering the input better than I did in the example code.

Related

serial.parseInt() returns a 0 value on its own

I am trying to read some integers from serial, so I used Serial.parseInt() to read two values(0 or 1), the thing is the code runs perfectly for the first time, but then the serial start reading the value 0 on its own, without me sending anything, here is part of the code I am using:
while (!Serial.available()) {}
A = Serial.parseInt();
Serial.println(A);
if (A == 1) {
Book = "";
Serial.println("add tag");
while (Book == "") {
delay(2000);
Book = tagB();
}
Serial.println(Book);
sendToE1("", Book);
delay(2000);
}
}
}
Serial.parseInt returns 0 when it times out with none or invalid characters received.
As you're loop is waiting for available data befor you call Serial.parseInt the only explanation is that you're sending something else but numbers. Most likely a linefeed or carriage return from your terminal program or a println function...
You should probably call Serial.peek to check if the next byte is a number befor you call Serial.parseInt. If you know for sure that you did not send anything but that single integer and some non-numeric character you can also clear the input buffer befor parsing a possible next integer.
But if you're sending an integer and a termination character you might as well just not use Serial.parseInt. Read your data into an array until you receive the termination character. Then convert your data to an integer yourself.
Using Serial.parseInt only makes sense if you know you're about to receive an integer representation within a certain time interval.
You probably need to set the monitor to "No line ending".

Arduino: while (Serial.available()==0) gives input

I am trying to input GPS coordinate into the serial monitor to use in my drone project
However, whenever I try to input GPS coordinate, it automatically writes one of the GPS coordinates without my input. For example, GPS latitude is shown as 0.00, but the program waits for GPS Longitude info.
For a detailed situation please look at the picture attached.
int GPSNumCor;
void setup() {
// put your setup code here, to run once:
Serial.begin (115200);
Serial.print("What is the number of your GPS Coordinate? ");
while (Serial.available() == 0);
GPSNumCor = Serial.parseInt();
Serial.println(GPSNumCor);
delay (200);
float GPSLat[GPSNumCor], GPSLon[GPSNumCor];
for (int i = 0; i < GPSNumCor; i++)
{
if (i == 0)
{
Serial.println("What is your 1st GPS Coordinate");
}
if (i == 1)
{
Serial.println("What is your 2nd GPS Coordinate");
}
if (i == 2)
{
Serial.println("What is your 3rd GPS Coordinate");
}
if (i > 2)
{
Serial.print("What is your ");
Serial.print(i + 1);
Serial.println(" th GPS Coordinate");
}
delay(200);
Serial.print ("Latitude: ");
while (Serial.available() == 0);
GPSLat[i] = Serial.parseFloat();
Serial.println(GPSLat[i]);
Serial.print("Longitude: ");
while (Serial.available() == 0);
GPSLon[i] = Serial.parseFloat();
Serial.println(GPSLon[i]);
}
}
It has to wait for all input until I make an input to the program, but it does not wait.
I know while (Serial.available()==0) is a way to go, but I do not know why it would not work.
First, there's no reason to use while (Serial.available() == 0);. The parseFloat function you are about to use waits for data to be available and, if it didn't, merely checking for zero wouldn't be sufficient anyway because that would stop waiting as soon as a single character was available.
So here's why that while loop is a bad idea:
If you really do need to wait for the input before calling parseFloat, this won't do it. It only waits until at least one character is received and the coordinates may be more than one character.
The parseFloat function doesn't return until it has read an entire float anyway. So it already waits for you.
But that's not your problem. Think about the input stream, say it's "11.0<newline>22.0newline44.0". Where is the code to read the spaces between those numbers? When parseFloat tries to read a space, it returns a zero, as the documentation says. That's why you're getting zeroes -- you don't have any code to do anything with the separators between the floats.
Think about how parseFloat must work when it reads "12.34newline". First it reads the 1 and has no idea whether that's the whole number of not, so it keeps checking. Then it reads the "2.34" and still has no idea it has the whole number. Not until it sees the newline does it know that 12.34 is the correct float to return. But it does not consume the newline. Why? Because that might mean something.
With the code you showed, your next call to parseFloat will then try to read the newline and see that this is not a valid character to be part of a floating point number. So, as the documentation says, it will return zero.
Look closely at parseFloat's documentation to find out how to correctly match the delimiters in your serial stream. The parseFloat function has the ability to behave differently, consuming and ignoring delimeters rather than returning zero.
I don't know how it work, I just add Serial.read() in every time I want to read.
If u don't want to add Serial.read(), u can also use old version like 1.6.0, it still work fine but it don't work when u make like C# Serial app.
Just add Serial.read(), it work fine every place.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
while(Serial.available()==0){}
int r=Serial.parseInt();
Serial.println(r);
Serial.read(); // it work fine
while(Serial.available()==0){}
int g=Serial.parseInt();
Serial.println(g);
Serial.read();
}
In the Serial Monitor window, in the drop-down menu on the bottom-right, change from "Newline" to "No line ending" and that will solve the problem (by preventing the Serial Monitor from automatically entering zero value(s)).
Both the parseInt() and parseFloat() have a hard time reading other data types (this also includes white spaces such as new lines) than the ones specified, and as a result they automatically return zero.
Reference: This page on Programming electronics offers valuable, detailed explanations (look for a paragraph with bold text):
https://www.programmingelectronics.com/parseint/

My Qt app does not recieve all the data sent by arduino

I'll go right to the point. My arduino reads values from the adc port and send them via serial port(values from 0 to 255). I save them in a byte type vector. After sending an specific signal to arduino, it starts to send to Qt app the data saved in the vector. Everything is working except that the arduino should send 800 values and the app receives less values than that. If I set the serial baud rate to 9600, I get 220 values. If, instead, I set the baud rate to 115200, I get only 20 values. Can you guys help me to fix this? I would like to use 115200 baud rate, because I need a good trasmision speed at this project(Real time linear CCD). I'll leave some code below:
Arduino code:
void sendData(void)
{
int x;
for (x = 0; x < 800; ++x)
{
Serial.print(buffer[x]);
}
}
This is the function that sends the values. I think is enough information, so I summarized it. If you need more code, please let me know.
Qt serial port setting code:
...
// QDialog windows private variables and constants
QSerialPort serial;
QSerialPortInfo serialInfo;
QList<QSerialPortInfo> listaPuertos;
bool estadoPuerto;
bool dataAvailable;
const QSerialPort::BaudRate BAUDRATE = QSerialPort::Baud9600;
const QSerialPort::DataBits DATABITS = QSerialPort::Data8;
const QSerialPort::Parity PARITY = QSerialPort::NoParity;
const QSerialPort::StopBits STOPBITS = QSerialPort::OneStop;
const QSerialPort::FlowControl FLOWCONTROL = QSerialPort::NoFlowControl;
const int pixels = 800;
QVector<double> data;
unsigned int dataIndex;
QByteArray values;
double maximo;
...
// Signal and slot connection.
QObject::connect(&serial, SIGNAL(readyRead()), this,SLOT(fillDataBuffer()));
...
// Method called when there's data available to read at the serial port.
void Ventana::fillDataBuffer()
{
dataIndex++;
data.append(QString::fromStdString(serial.readAll().toStdString()).toDouble());
if(data.at(dataIndex-1) > maximo) maximo = data.at(dataIndex-1);
/* The following qDebug is the one I use to test the recieved values,
* where I check that values. */
qDebug() << data.at(dataIndex-1);
}
Thanks and sorry if it's not so clear, it has been an exhausting day :P
Ok... I see two probelms here:
Arduino side: you send your data in a decimal form (so x = 100 will be sent as 3 characters - 1, 0 and 0. You have no delimiter between your data, so how your receiver will know that it received value 100 not three values 1, 0 and 0? Please see my answer here for further explanation on how to send ADC data from Arduino.
QT side: There is no guarantee on the moment when readyRead() signal will be triggered. It may be immediately after first sample arrives, but it may be raised after there are already couple of samples inside the serial port buffer. If that happens, your method fillDataBuffer() may process string 12303402 instead of four separate strings 123, 0, 340 and 2, because between two buffer reads four samples arrived. The bigger the baudrate, the more samples will arrive between the reads, which is why you observe less values with a bigger baud rate.
Solution for both of your problems is to append some delimiting byte for your data, and split the string in the buffer on that delimiting byte. If you don't want to have maximum data throughput, you can just do
Serial.print(buffer[x]);
Serial.print('\n');
and then, split incoming string on \n character.
Thank you very much! I did what you said about my arduino program and after solving that, I was still not getting the entire amount of data. So the the problem was in Qt. How you perfectly explain, the serial buffer was accumulating the values too fast, so the slot function "fillDataBuffer()" was too slow to process the arriving data. I simplified that function:
void Ventana::fillDataBuffer()
{
dataIndex++;
buffer.append(serial.readAll());
}
After saving all the values in the QByteArray buffer, I process the data separately.
Thanks again man. Your answer was really helpful.

How to capture a variable stream of characters and process them on a Arduino using serial?

I'm trying to read variable streams of characters and process them on the Arduino once a certain string of bytes is read on the Arduino. I have a sample sketch like the following, but I can't figure out how to compare the "readString" to process something on the Arduino. I would like the Arduino to process "commands" such as {blink}, {open_valve}, {close_valve}, etc.
// Serial - read bytes into string variable for string
String readString;
// Arduino serial read - example
int incomingByte;
// flow_A LED
int led = 4;
void setup() {
Serial.begin(2400); // Open serial port and set Baud rate to 2400.
Serial.write("Power on test");
}
void loop() {
while (Serial.available()) {
delay(10);
if (Serial.available() > 0) {
char c = Serial.read(); // Gets one byte from serial buffer
readString += c; // Makes the string readString
}
}
if (readString.length() > 0) {
Serial.println( readString); // See what was received
}
if (readString == '{blink_Flow_A}') {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level).
delay(1000); // Wait for one second.
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW.
delay(1000); // Wait for a second.
}
Some definitions first:
SOP = Start Of Packet (in your case, an opening brace)
EOP = End Of Packet (in your case, a closing brace)
PAYLOAD = the characters between SOP and EOP
PACKET = SOP + PAYLOAD + EOP
Example:
PACKET= {Abc}
SOP = {
EOP = }
PAYLOAD = Abc
Your code should process one character at a time, and should be structured as a state machine.
When the code starts, the parser state is "I'm waiting for the SOP character". While in this state, you throw away every character you receive unless it's equal to SOP.
When you find you received a SOP char, you change the parser state to "I'm receiving the payload". You store every character from now on into a buffer, until you either see an EOP character or exhaust the buffer (more on this in a moment). If you see the EOP char, you "close" the buffer by appending a NULL character (i.e. 0x00) so that it becomes a standard NULL-terminated C-string, and you can work on it with the standard functions (strcmp, strstr, strchr, etc.).
At this point you pass the buffer to a "process()" function, which executes the operation specified by the payload (1)
You have to specify the maximum length of a packet, and size the receive buffer accordingly. You also have to keep track of the current payload length during the "payload receive" state, so you don't accidentally try to store more payload bytes into the temporary buffer than it can hold (otherwise you get memory corruption).
If you fill the receive buffer without seeing an EOP character, then that packet is either malformed (too long) or a transmission error changed the EOP character into something else. In either case you should discard the buffer contents and go back to "Waiting for SOP" state.
Depending on the protocol design, you could send an error code to the PC so the person typing at the terminal or the software on that side knows the last command it sent was invalid or not received correctly.
Finally, the blink code in you snipped should be replaced by non-blocking "blink-without-delay"-style code (look at the example that come with the Arduino IDE).
(1) Example of a "process" function:
void process(char* cmd) {
if (strcmp(cmd, "open_valve") == 0) {
open_valve();
}
else if (strcmp(cmd, "close_valve") == 0) {
close_valve();
}
else {
print_error("Unrecognized command.");
}
}
It seems you are comparing the string in this statement:
if( readString == '{blink_Flow_A}' )
So I don't get your question re :
but I can't figure out how to compare the "readString" to process something
Are you really asking:
How do I extract the commands from an incoming stream of characters?
If that is the case then treat each command as a "packet". The packet is enclosed in brackets: {}. Knowing that the {} brackets are start and end of a packet, it is easy to write a routine to get at the command in the packet.
Once the command is extracted just go through a if-then-else statement to do what each command is supposed to do.
If I totally misunderstood your question I apologize :)
EDIT:
see http://arduino.cc/en/Tutorial/StringComparisonOperators
if( readString == "{blink_Flow_A}" ) should be correct syntax.
Since you have a statement
Serial.println( readString);
you should see the string received.

Arduino serial data parsing

I'm writing an app to control my robot with my Android phone over Bluetooth, everything is goes well, data is echoed and verified, but I'm having some trouble with the protocol, specifically I want my robot's wheels to turn when I send a command such as s,10,100 or s,-30,-10... (values in percent).
My problem is that when I want to parse my wheel speed command on my Arduino I must parse from up to 4 separate bytes to int, for example s,-100,-100 makes my robot go backwards at full speed, but how do I parse this so I can call setSpeed(left, right); with leftand right equal to -100?
I know I can separately analyse every byte and put them together to get an integer, but it's not very elegant and there's probably a better solution to all this already, unfortunately I haven't found it yet.
EDIT
Here's my Arduino function for parsing my commands:
void parseCommand(char* command, int* returnValues)
{
// parsing state machine
byte i = 2, j = 0, sign = 0;
int temp = 0;
while(*(command + i) != '\0')
{
switch(*(command + i))
{
case ',':
returnValues[j++] = sign?-temp:temp;
sign = 0;
temp = 0;
break;
case '-':
sign = 1;
break;
default:
temp = temp * 10 + *(command + i) - 48;
}
i++;
}
// set last return value
returnValues[j] = sign?-temp:temp;
}
You call it this way when parsing something like s,100,-100 (must be \0 terminated):
char serialData[16];
void loop()
{
if(Serial.available() > 0)
{
Serial.readBytesUntil('\0', serialData, 15);
switch(serialData[0])
{
case 's':
int speed[2];
parseCommand(serialData, speed);
setSpeed(speed[0], speed[1]);
break;
}
// always echo
Serial.write(serialData);
// end of message is maked with a \0
Serial.print('\0');
// clear serialData array
memset(serialData, 0, sizeof(serialData));
}
}
Just read character by character into a state machine. It's simple and efficient.
To read in a number digit by digit, do this: Start with zero. For each digit, multiply the number by ten and add the value of the digit. So, for example, reading 97 would work like this:
You read in a digit with no prior digit, you start with 0.
You read in 9 and compute (0*10)+9 -> 9
You read in 7 and compute (9*10)+7 -> 97
You read in a non-digit, you output the 97.
Here's a fuller example s,10,100:
You start in the "ready to read command state".
You read "s", "s" is the command. You switch to the "ready to read first comma" state.
You read the first comma, you switch to the "ready to figure out the sign of the first parameter" state.
You read a digit. Since this wasn't a "-", the first parameter is positive. You set the first number to the value of the digit, 1. You are now in "reading first number" state.
You read a digit, 0. You set the first number to 1*10+0 -> 10. You are still in "reading first number" state.
You read a comma. You are now in the "ready to figure out sign of the second parameter" state.
You read 1. The second number is positive (since this wasn't a "-"). You set the second number to 1. You are in the "reading second number" state.
You read 0. The second number is now set to 1x10+0 -> 10. You are still in "reading second number" state.
You read 0. The second number is now set to 10x10+0 -> 100. You are still in "reading second number" state.
You read an end of line. You execute your results: The command is "s", the first number is positive, the first number is 10, the second number is positive, the second number is 100.
You switch back to "ready to read command" state.
I like the answer by David Swartz, but thought I'd play devil's advocate.
Reading the data in as binary can be elegant, it just depends on what you need to do with it.
In the following example, data is read from serial until it sees the binary delimiter 0X7F. The bytes read are stored in the inData char array. Take a look at the documentation for Serial.readBytesUntil()
char inData[16];
int bRead;
bRead = Serial.readBytesUntil(0x7F,inData,4);
This byte can then be cast to an integer or otherwise manipulated. Keep in mind the maximum value for this would be +/-126 because this is a signed char (127 is a delimiter and wouldn't be seen as a value).
You could access these values by with something like the following:
Serial.print("Bytes Read: ");
Serial.println(bRead);
Serial.println("First Byte");
Serial.println((int)inData[0]);
Serial.println(
map((int)inData[0],0,126,0,1024)
);
Serial.println("Second Byte");
Serial.println((int)inData[1]);
I tested this out with the following bash command (after making sure serial speeds were set properly):
echo -ne '\x01\x02\x7F' > /dev/ttyACM0
Some rough sample code that I wrote can be found Here

Resources